diff --git a/src/DataPersister/ProxyDataPersister.php b/src/DataPersister/ProxyDataPersister.php
index 4e597cb255aa660fd56abd9199746cb31c93d3b1..07bcfdf5523541f512a3975b8f710ca09c006eb0 100644
--- a/src/DataPersister/ProxyDataPersister.php
+++ b/src/DataPersister/ProxyDataPersister.php
@@ -5,10 +5,12 @@ declare(strict_types=1);
 namespace Dbp\Relay\ProxyBundle\DataPersister;
 
 use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
+use Dbp\Relay\CoreBundle\Helpers\Tools;
 use Dbp\Relay\ProxyBundle\Entity\ProxyData;
 use Dbp\Relay\ProxyBundle\Event\ProxyDataEvent;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\HttpFoundation\Exception\BadRequestException;
 
 class ProxyDataPersister extends AbstractController implements ContextAwareDataPersisterInterface
 {
@@ -32,8 +34,19 @@ class ProxyDataPersister extends AbstractController implements ContextAwareDataP
     {
         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
 
-        $proxyDataEvent = new ProxyDataEvent($data);
-        $this->eventDispatcher->dispatch($proxyDataEvent, ProxyDataEvent::NAME.$data->getNamespace());
+        if (Tools::isNullOrEmpty($data->getNamespace())) {
+            throw new BadRequestException('parameter namespace must not be null nor empty');
+        } elseif (Tools::isNullOrEmpty($data->getFunctionName())) {
+            throw new BadRequestException('parameter functionName must not be null nor empty');
+        } else {
+            $proxyDataEvent = new ProxyDataEvent($data);
+            $this->eventDispatcher->dispatch($proxyDataEvent, ProxyDataEvent::NAME.$data->getNamespace());
+
+            if ($proxyDataEvent->wasHandled() === false) {
+                throw new BadRequestException(sprintf('unknown namespace "%s"', $data->getNamespace()));
+            }
+        }
+
         $data->setIdentifier($data->getNamespace().'::'.$data->getFunctionName());
 
         return $data;
diff --git a/src/Entity/ProxyData.php b/src/Entity/ProxyData.php
index 791f944fe33abf25982ac6c1de20a0ab61204280..a73602ad482fd4f629baf27e51814d85056099ec 100644
--- a/src/Entity/ProxyData.php
+++ b/src/Entity/ProxyData.php
@@ -147,7 +147,7 @@ class ProxyData
         $this->errors = $errors;
     }
 
-    public function getFunctionName(): string
+    public function getFunctionName(): ?string
     {
         return $this->functionName;
     }
@@ -157,7 +157,7 @@ class ProxyData
         $this->functionName = $functionName;
     }
 
-    public function getNamespace(): string
+    public function getNamespace(): ?string
     {
         return $this->namespace;
     }
diff --git a/src/Event/ProxyDataEvent.php b/src/Event/ProxyDataEvent.php
index 65932072cf1f0af029602962f81fc31405484775..c3d12e15ab2eddb9bd02ed78fcb2a448dab8d01a 100644
--- a/src/Event/ProxyDataEvent.php
+++ b/src/Event/ProxyDataEvent.php
@@ -14,13 +14,33 @@ class ProxyDataEvent extends Event
     /** @var ProxyData */
     private $proxyData;
 
+    /** @var bool */
+    private $wasHandled;
+
     public function __construct(ProxyData $proxyData)
     {
         $this->proxyData = $proxyData;
+        $this->wasHandled = false;
     }
 
     public function getProxyData(): ProxyData
     {
         return $this->proxyData;
     }
+
+    /**
+     * Indicate, that the event was handled, e.g. there was an event subscriber for the requested proxy data namespace.
+     */
+    public function setHandled(): void
+    {
+        $this->wasHandled = true;
+    }
+
+    /**
+     * True, if the event was handled, e.g. there was an event subscriber for the requested proxy data namespace, false otherwise.
+     */
+    public function wasHandled(): bool
+    {
+        return $this->wasHandled;
+    }
 }
diff --git a/src/EventSubscriber/ProxyDataEventSubscriber.php b/src/EventSubscriber/ProxyDataEventSubscriber.php
new file mode 100644
index 0000000000000000000000000000000000000000..2bc93fe5d849adf95bc663fc5956e614fe8c7fdd
--- /dev/null
+++ b/src/EventSubscriber/ProxyDataEventSubscriber.php
@@ -0,0 +1,54 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Dbp\Relay\ProxyBundle\EventSubscriber;
+
+use Dbp\Relay\ProxyBundle\Event\ProxyDataEvent;
+use Exception;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\Exception\BadRequestException;
+
+abstract class ProxyDataEventSubscriber implements EventSubscriberInterface
+{
+    protected const NAMESPACE = '';
+
+    public static function getSubscribedEvents(): array
+    {
+        return [
+            ProxyDataEvent::NAME.static::NAMESPACE => 'onProxyDataEvent',
+        ];
+    }
+
+    /**
+     * @throws BadRequestException
+     */
+    public function onProxyDataEvent(ProxyDataEvent $event): void
+    {
+        $event->setHandled();
+        $proxyData = $event->getProxyData();
+        $functionName = $proxyData->getFunctionName();
+        $arguments = $proxyData->getArguments();
+        $returnValue = null;
+
+        if ($this->isFunctionDefined($functionName) === false) {
+            throw new BadRequestException(sprintf('unknown function "%s" under namespace "%s"', $functionName, static::NAMESPACE));
+        } elseif ($this->areAllRequiredArgumentsDefined($arguments) === false) {
+            throw new BadRequestException(sprintf('incomplete argument list for function "%s" under namespace "%s"', $functionName, static::NAMESPACE));
+        }
+
+        try {
+            $returnValue = $this->callFunction($functionName, $arguments);
+        } catch (Exception $exception) {
+            $proxyData->setErrorsFromException($exception);
+        }
+
+        $proxyData->setData($returnValue);
+    }
+
+    abstract protected function isFunctionDefined(string $functionName): bool;
+
+    abstract protected function areAllRequiredArgumentsDefined(array $arguments): bool;
+
+    abstract protected function callFunction(string $functionName, array $arguments);
+}