public function route(RequestInterface $request, ResponseInterface $response, Context $context = null)
    {
        $this->level++;

        $this->eventDispatcher->dispatch(Event::REQUEST_INCOMING, new RequestIncomingEvent($request));

        // load controller
        if ($context === null) {
            $factory = $this->config->get('psx_context_factory');
            if ($factory instanceof \Closure) {
                $context = $factory();
            } else {
                $context = new Context();
            }
        }

        try {
            $this->loader->load($request, $response, $context);
        } catch (StatusCode\NotModifiedException $e) {
            $response->setStatus($e->getStatusCode());
            $response->setBody(new StringStream());
        } catch (StatusCode\RedirectionException $e) {
            $response->setStatus($e->getStatusCode());
            $response->setHeader('Location', $e->getLocation());
            $response->setBody(new StringStream());
        } catch (\Throwable $e) {
            $this->eventDispatcher->dispatch(Event::EXCEPTION_THROWN, new ExceptionThrownEvent($e, new ControllerContext($request, $response)));

            $this->handleException($e, $response);

            try {
                $context->setException($e);

                $class      = isset($this->config['psx_error_controller']) ? $this->config['psx_error_controller'] : ErrorController::class;
                $controller = $this->controllerFactory->getController($class, $context);

                $this->loader->execute($controller, $request, $response);
            } catch (\Throwable $e) {
                // in this case the error controller has thrown an exception.
                // This can happen i.e. if we can not represent the error in an
                // fitting media type. In this case we send json to the client

                $this->handleException($e, $response);

                $record = $this->exceptionConverter->convert($e);

                $response->setHeader('Content-Type', 'application/json');
                $response->setBody(new StringStream(Parser::encode($record, JSON_PRETTY_PRINT)));
            }
        }

        // for HEAD requests we never return a response body
        if ($request->getMethod() == 'HEAD') {
            $response->setHeader('Content-Length', $response->getBody()->getSize());
            $response->setBody(new StringStream(''));
        }

        $this->eventDispatcher->dispatch(Event::RESPONSE_SEND, new ResponseSendEvent($response));

        $this->level--;

        return $response;
    }