diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6137523..7446c4f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-# Yii debug API Change Log
+# Yii Debug API Change Log
 
 ## 1.0.0 under development
 
diff --git a/LICENSE.md b/LICENSE.md
index bc5674f..c48bcea 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,4 +1,4 @@
-Copyright © 2008 by Yii Software (https://www.yiiframework.com/)
+Copyright © 2008 by Yii Software (<https://www.yiiframework.com/>)
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index 27deffb..1da8802 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
 <p align="center">
     <a href="https://github.com/yiisoft" target="_blank">
-        <img src="https://github.com/yiisoft.png" height="100px">
+        <img src="https://yiisoft.github.io/docs/images/yii_logo.svg" height="100px" alt="Yii">
     </a>
-    <h1 align="center">Yii debug API</h1>
+    <h1 align="center">Yii Debug API</h1>
     <br>
 </p>
 
@@ -22,7 +22,7 @@ This extension provides an API for [Yii Debug](https://github.com/yiisoft/yii-de
 
 ## Installation
 
-Add the package to your application:
+The package could be installed with [Composer](https://getcomposer.org):
 
 ```shell
 composer require yiisoft/yii-debug-api
@@ -33,31 +33,12 @@ composer require yiisoft/yii-debug-api
 Routes will be registered automatically within Yii application router.
 You can check if everything is OK by going to `/debug` URL.
 
-## Testing
+## Documentation
 
-### Unit testing
+- [Internals](docs/internals.md)
 
-The package is tested with [PHPUnit](https://phpunit.de/). To run tests:
-
-```shell
-./vendor/bin/phpunit
-```
-
-### Mutation testing
-
-The package tests are checked with [Infection](https://infection.github.io/) mutation framework. To run it:
-
-```shell
-./vendor/bin/infection
-```
-
-### Static analysis
-
-The code is statically analyzed with [Psalm](https://psalm.dev/). To run static analysis:
-
-```shell
-./vendor/bin/psalm
-```
+If you need help or have a question, the [Yii Forum](https://forum.yiiframework.com/c/yii-3-0/63) is a good place for that.
+You may also check out other [Yii Community Resources](https://www.yiiframework.com/community).
 
 ## License
 
@@ -65,3 +46,15 @@ The Yii Debug API is free software. It is released under the terms of the BSD Li
 Please see [`LICENSE`](./LICENSE.md) for more information.
 
 Maintained by [Yii Software](https://www.yiiframework.com/).
+
+## Support the project
+
+[![Open Collective](https://img.shields.io/badge/Open%20Collective-sponsor-7eadf1?logo=open%20collective&logoColor=7eadf1&labelColor=555555)](https://opencollective.com/yiisoft)
+
+## Follow updates
+
+[![Official website](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](https://www.yiiframework.com/)
+[![Twitter](https://img.shields.io/badge/twitter-follow-1DA1F2?logo=twitter&logoColor=1DA1F2&labelColor=555555?style=flat)](https://twitter.com/yiiframework)
+[![Telegram](https://img.shields.io/badge/telegram-join-1DA1F2?style=flat&logo=telegram)](https://t.me/yii3en)
+[![Facebook](https://img.shields.io/badge/facebook-join-1DA1F2?style=flat&logo=facebook&logoColor=ffffff)](https://www.facebook.com/groups/yiitalk)
+[![Slack](https://img.shields.io/badge/slack-join-1DA1F2?style=flat&logo=slack)](https://yiiframework.com/go/slack)
diff --git a/composer-require-checker.json b/composer-require-checker.json
index 23b3346..0528b49 100644
--- a/composer-require-checker.json
+++ b/composer-require-checker.json
@@ -4,6 +4,7 @@
         "Yiisoft\\Assets\\AssetManager",
         "Yiisoft\\Assets\\AssetPublisherInterface",
         "Yiisoft\\Yii\\View\\ViewRenderer",
+        "Yiisoft\\Yii\\Http\\Application",
         "Codeception\\Event\\FailEvent",
         "Codeception\\Event\\PrintResultEvent",
         "Codeception\\Event\\TestEvent",
diff --git a/composer.json b/composer.json
index 8fba472..9823507 100644
--- a/composer.json
+++ b/composer.json
@@ -13,12 +13,22 @@
     "license": "BSD-3-Clause",
     "support": {
         "issues": "https://github.com/yiisoft/yii-debug-api/issues?state=open",
+        "source": "https://github.com/yiisoft/yii-debug-api",
         "forum": "https://www.yiiframework.com/forum/",
         "wiki": "https://www.yiiframework.com/wiki/",
-        "irc": "irc://irc.freenode.net/yii",
-        "chat": "https://t.me/yii3en",
-        "source": "https://github.com/yiisoft/yii-debug-api"
+        "irc": "ircs://irc.libera.chat:6697/yii",
+        "chat": "https://t.me/yii3en"
     },
+    "funding": [
+        {
+            "type": "opencollective",
+            "url": "https://opencollective.com/yiisoft"
+        },
+        {
+            "type": "github",
+            "url": "https://github.com/sponsors/yiisoft"
+        }
+    ],
     "minimum-stability": "dev",
     "prefer-stable": true,
     "require": {
@@ -27,9 +37,10 @@
         "gitonomy/gitlib": "^1.3",
         "guzzlehttp/guzzle": "^7.5",
         "guzzlehttp/psr7": "^2.4",
+        "httpsoft/http-message": "^1.1",
         "psr/container": "^2.0",
         "psr/http-factory": "^1.0",
-        "psr/http-message": "^1.0",
+        "psr/http-message": "^1.0|^2.0",
         "psr/http-server-handler": "^1.0",
         "psr/http-server-middleware": "^1.0",
         "psr/simple-cache": "^2.0|^3.0",
@@ -40,6 +51,7 @@
         "yiisoft/di": "^1.0",
         "yiisoft/friendly-exception": "^1.1",
         "yiisoft/http": "^1.2",
+        "yiisoft/middleware-dispatcher": "^5.2",
         "yiisoft/router": "^3.0",
         "yiisoft/translator": "^3.0",
         "yiisoft/var-dumper": "^1.4",
@@ -55,12 +67,14 @@
         "roave/infection-static-analysis-plugin": "^1.16",
         "spatie/phpunit-watcher": "^1.23",
         "vimeo/psalm": "^5.22",
-        "yiisoft/active-record": "3.0.x-dev",
+        "yiisoft/active-record": "dev-master",
         "yiisoft/assets": "^4.0",
         "yiisoft/csrf": "^2.0",
+        "yiisoft/db": "1.2 as dev-master",
         "yiisoft/db-sqlite": "^1.0",
         "yiisoft/psr-dummy-provider": "^1.0",
         "yiisoft/router-fastroute": "^3.0",
+        "yiisoft/test-support": "^3.0",
         "yiisoft/yii-cycle": "dev-master",
         "yiisoft/yii-view": "^6.0"
     },
diff --git a/config/di-web.php b/config/di-web.php
index 4836e98..1e17aec 100644
--- a/config/di-web.php
+++ b/config/di-web.php
@@ -5,6 +5,8 @@
 use Cycle\Database\DatabaseProviderInterface;
 use Psr\Container\ContainerInterface;
 use Yiisoft\Db\Connection\ConnectionInterface;
+use Yiisoft\Yii\Debug\Api\Debug\Http\HttpApplicationWrapper;
+use Yiisoft\Yii\Debug\Api\Debug\Http\RouteCollectorWrapper;
 use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepository;
 use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepositoryInterface;
 use Yiisoft\Yii\Debug\Api\Inspector\Database\Cycle\CycleSchemaProvider;
@@ -34,4 +36,14 @@
             )
         );
     },
+    HttpApplicationWrapper::class => [
+        '__construct()' => [
+            'middlewareDefinitions' => $params['yiisoft/yii-debug-api']['middlewares'],
+        ],
+    ],
+    RouteCollectorWrapper::class => [
+        '__construct()' => [
+            'middlewareDefinitions' => $params['yiisoft/yii-debug-api']['middlewares'],
+        ],
+    ],
 ];
diff --git a/config/params.php b/config/params.php
index b6c42ba..9630fc8 100644
--- a/config/params.php
+++ b/config/params.php
@@ -3,6 +3,7 @@
 declare(strict_types=1);
 
 use Codeception\Extension;
+use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders;
 use Yiisoft\Yii\Debug\Api\Inspector\Command\CodeceptionCommand;
 use Yiisoft\Yii\Debug\Api\Inspector\Command\PHPUnitCommand;
 use Yiisoft\Yii\Debug\Api\Inspector\Command\PsalmCommand;
@@ -26,6 +27,9 @@
         'enabled' => true,
         'allowedIPs' => ['127.0.0.1', '::1'],
         'allowedHosts' => [],
+        'middlewares' => [
+            DebugHeaders::class,
+        ],
         'inspector' => [
             'commandMap' => [
                 'tests' => $testCommands,
diff --git a/docs/internals.md b/docs/internals.md
new file mode 100644
index 0000000..087a514
--- /dev/null
+++ b/docs/internals.md
@@ -0,0 +1,44 @@
+# Internals
+
+## Unit testing
+
+The package is tested with [PHPUnit](https://phpunit.de/). To run tests:
+
+```shell
+./vendor/bin/phpunit
+```
+
+## Mutation testing
+
+The package tests are checked with [Infection](https://infection.github.io/) mutation framework with
+[Infection Static Analysis Plugin](https://github.com/Roave/infection-static-analysis-plugin). To run it:
+
+```shell
+./vendor/bin/roave-infection-static-analysis-plugin
+```
+
+## Static analysis
+
+The code is statically analyzed with [Psalm](https://psalm.dev/). To run static analysis:
+
+```shell
+./vendor/bin/psalm
+```
+
+## Code style
+
+Use [Rector](https://github.com/rectorphp/rector) to make codebase follow some specific rules or
+use either newest or any specific version of PHP:
+
+```shell
+./vendor/bin/rector
+```
+
+## Dependencies
+
+This package uses [composer-require-checker](https://github.com/maglnet/ComposerRequireChecker) to check if
+all dependencies are correctly defined in `composer.json`. To run the checker, execute the following command:
+
+```shell
+./vendor/bin/composer-require-checker
+```
diff --git a/src/Debug/Http/HttpApplicationWrapper.php b/src/Debug/Http/HttpApplicationWrapper.php
new file mode 100644
index 0000000..c3b9b5a
--- /dev/null
+++ b/src/Debug/Http/HttpApplicationWrapper.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Debug\Http;
+
+use Closure;
+use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
+use Yiisoft\Yii\Debug\Api\Debug\Middleware\MiddlewareDispatcherMiddleware;
+use Yiisoft\Yii\Http\Application;
+
+final readonly class HttpApplicationWrapper
+{
+    public function __construct(
+        private MiddlewareDispatcher $middlewareDispatcher,
+        private array $middlewareDefinitions,
+    ) {
+    }
+
+    public function wrap(Application $application): void
+    {
+        $middlewareDispatcher = $this->middlewareDispatcher;
+        $middlewareDefinitions = $this->middlewareDefinitions;
+
+        $closure = Closure::bind(static function (Application $application) use (
+            $middlewareDispatcher,
+            $middlewareDefinitions,
+        ) {
+            $application->dispatcher = $middlewareDispatcher->withMiddlewares([
+                ...$middlewareDefinitions,
+                ['class' => MiddlewareDispatcherMiddleware::class, '$middlewareDispatcher' => $application->dispatcher],
+            ]);;
+        }, null, $application);
+
+        $closure($application);
+    }
+}
diff --git a/src/Debug/Http/RouteCollectorWrapper.php b/src/Debug/Http/RouteCollectorWrapper.php
new file mode 100644
index 0000000..c31fe75
--- /dev/null
+++ b/src/Debug/Http/RouteCollectorWrapper.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Debug\Http;
+
+use Yiisoft\Router\RouteCollectorInterface;
+
+final class RouteCollectorWrapper
+{
+    public function __construct(
+        private array $middlewareDefinitions,
+    ) {
+    }
+
+    public function wrap(RouteCollectorInterface $routeCollector): void
+    {
+        $routeCollector->prependMiddleware(...$this->middlewareDefinitions);
+    }
+}
diff --git a/src/Debug/Middleware/MiddlewareDispatcherMiddleware.php b/src/Debug/Middleware/MiddlewareDispatcherMiddleware.php
new file mode 100644
index 0000000..4cdaf74
--- /dev/null
+++ b/src/Debug/Middleware/MiddlewareDispatcherMiddleware.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Debug\Middleware;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
+
+final class MiddlewareDispatcherMiddleware implements MiddlewareInterface
+{
+    public function __construct(
+        public MiddlewareDispatcher $middlewareDispatcher
+    ) {
+    }
+
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        return $this->middlewareDispatcher->dispatch($request, $handler);
+    }
+}
diff --git a/src/Debug/Provider/DebugApiProvider.php b/src/Debug/Provider/DebugApiProvider.php
index d62d5be..7de2b6a 100644
--- a/src/Debug/Provider/DebugApiProvider.php
+++ b/src/Debug/Provider/DebugApiProvider.php
@@ -7,7 +7,9 @@
 use Psr\Container\ContainerInterface;
 use Yiisoft\Di\ServiceProviderInterface;
 use Yiisoft\Router\RouteCollectorInterface;
-use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders;
+use Yiisoft\Yii\Debug\Api\Debug\Http\HttpApplicationWrapper;
+use Yiisoft\Yii\Debug\Api\Debug\Http\RouteCollectorWrapper;
+use Yiisoft\Yii\Http\Application;
 
 final class DebugApiProvider implements ServiceProviderInterface
 {
@@ -22,10 +24,24 @@ public function getDefinitions(): array
     public function getExtensions(): array
     {
         return [
-            RouteCollectorInterface::class => static function (ContainerInterface $container, RouteCollectorInterface $routeCollector) {
-                $routeCollector->prependMiddleware(DebugHeaders::class);
+            RouteCollectorInterface::class => static function (
+                ContainerInterface $container,
+                RouteCollectorInterface $routeCollector
+            ) {
+                /**
+                 * Register debug middlewares twice because a `Subfolder` middleware may rewrite base URL
+                 */
+                $routerCollectionWrapper = $container->get(RouteCollectorWrapper::class);
+                $routerCollectionWrapper->wrap($routeCollector);
+
                 return $routeCollector;
             },
+            Application::class => static function (ContainerInterface $container, Application $application) {
+                $applicationWrapper = $container->get(HttpApplicationWrapper::class);
+                $applicationWrapper->wrap($application);
+
+                return $application;
+            },
         ];
     }
 }
diff --git a/src/Debug/Repository/CollectorRepository.php b/src/Debug/Repository/CollectorRepository.php
index e37324b..777963e 100644
--- a/src/Debug/Repository/CollectorRepository.php
+++ b/src/Debug/Repository/CollectorRepository.php
@@ -38,7 +38,7 @@ public function getObject(string $id, string $objectId): array|null
         $dump = $this->loadData(StorageInterface::TYPE_OBJECTS, $id);
 
         foreach ($dump as $name => $value) {
-            if (($pos = strrpos($name, "#$objectId")) !== false) {
+            if (($pos = strrpos((string)$name, "#$objectId")) !== false) {
                 return [substr($name, 0, $pos), $value];
             }
         }
diff --git a/src/Inspector/ApplicationState.php b/src/Inspector/ApplicationState.php
index 9996b20..1b73fd2 100644
--- a/src/Inspector/ApplicationState.php
+++ b/src/Inspector/ApplicationState.php
@@ -4,7 +4,10 @@
 
 namespace Yiisoft\Yii\Debug\Api\Inspector;
 
-class ApplicationState
+/**
+ * @internal
+ */
+final class ApplicationState
 {
-    public static $params;
+    public static array $params = [];
 }
diff --git a/src/Inspector/Command/BashCommand.php b/src/Inspector/Command/BashCommand.php
index 357e056..9485c99 100644
--- a/src/Inspector/Command/BashCommand.php
+++ b/src/Inspector/Command/BashCommand.php
@@ -38,7 +38,7 @@ public function run(): CommandResponse
             ->setTimeout(null)
             ->run();
 
-        $processOutput = $process->getOutput();
+        $processOutput = rtrim($process->getOutput());
 
         if (!$process->getExitCode() > 1) {
             return new CommandResponse(
diff --git a/src/Inspector/Controller/InspectController.php b/src/Inspector/Controller/InspectController.php
index 860b3d0..cad40ef 100644
--- a/src/Inspector/Controller/InspectController.php
+++ b/src/Inspector/Controller/InspectController.php
@@ -307,7 +307,7 @@ public function routes(RouteCollectionInterface $routeCollection): ResponseInter
                 'methods' => $data['methods'],
                 'defaults' => $data['defaults'],
                 'override' => $data['override'],
-                'middlewares' => $data['middlewareDefinitions'],
+                'middlewares' => $data['middlewareDefinitions'] ?? [],
             ];
         }
         $response = VarDumper::create($routes)->asPrimitives(5);
diff --git a/tests/Support/Application/fail.sh b/tests/Support/Application/fail.sh
new file mode 100644
index 0000000..4bbf6fa
--- /dev/null
+++ b/tests/Support/Application/fail.sh
@@ -0,0 +1,2 @@
+echo 'failed'
+exit $1
diff --git a/tests/Support/StubCollector.php b/tests/Support/StubCollector.php
new file mode 100644
index 0000000..06abc04
--- /dev/null
+++ b/tests/Support/StubCollector.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Support;
+
+use Yiisoft\Yii\Debug\Collector\CollectorInterface;
+
+final class StubCollector implements CollectorInterface
+{
+    public function __construct(private array $data = [])
+    {
+    }
+
+    public function getName(): string
+    {
+        return 'stub';
+    }
+
+    public function startup(): void
+    {
+    }
+
+    public function shutdown(): void
+    {
+    }
+
+    public function getCollected(): array
+    {
+        return $this->data;
+    }
+}
diff --git a/tests/Unit/Debug/Middleware/DebugHeadersTest.php b/tests/Unit/Debug/Middleware/DebugHeadersTest.php
new file mode 100644
index 0000000..f86459a
--- /dev/null
+++ b/tests/Unit/Debug/Middleware/DebugHeadersTest.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Debug\Middleware;
+
+use HttpSoft\Message\Response;
+use HttpSoft\Message\ServerRequest;
+use PHPUnit\Framework\TestCase;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Yiisoft\Router\UrlGeneratorInterface;
+use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders;
+use Yiisoft\Yii\Debug\DebuggerIdGenerator;
+
+final class DebugHeadersTest extends TestCase
+{
+    public function testHeaders(): void
+    {
+        $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
+        $urlGenerator->method('generate')->willReturnCallback(
+            fn (string $route, array $parameters) => $route . '?' . http_build_query($parameters)
+        );
+        $idGenerator = new DebuggerIdGenerator();
+        $expectedId = $idGenerator->getId();
+
+        $middleware = new DebugHeaders($idGenerator, $urlGenerator);
+        $response = $middleware->process(new ServerRequest(), $this->createRequestHandler());
+
+        $this->assertSame($expectedId, $response->getHeaderLine('X-Debug-Id'));
+        $this->assertSame('debug/api/view?id=' . $expectedId, $response->getHeaderLine('X-Debug-Link'));
+    }
+
+    protected function createRequestHandler(): RequestHandlerInterface
+    {
+        return new class () implements RequestHandlerInterface {
+            public function handle($request): ResponseInterface
+            {
+                return new Response(200);
+            }
+        };
+    }
+}
diff --git a/tests/Unit/Debug/Middleware/ResponseDataWrapperTest.php b/tests/Unit/Debug/Middleware/ResponseDataWrapperTest.php
new file mode 100644
index 0000000..634cc66
--- /dev/null
+++ b/tests/Unit/Debug/Middleware/ResponseDataWrapperTest.php
@@ -0,0 +1,138 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Debug\Middleware;
+
+use HttpSoft\Message\Response;
+use HttpSoft\Message\ResponseFactory;
+use HttpSoft\Message\ServerRequest;
+use HttpSoft\Message\StreamFactory;
+use PHPUnit\Framework\TestCase;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Throwable;
+use Yiisoft\DataResponse\DataResponse;
+use Yiisoft\DataResponse\DataResponseFactory;
+use Yiisoft\Router\CurrentRoute;
+use Yiisoft\Yii\Debug\Api\Debug\Exception\NotFoundException;
+use Yiisoft\Yii\Debug\Api\Debug\Middleware\ResponseDataWrapper;
+
+final class ResponseDataWrapperTest extends TestCase
+{
+    public function testNotDataResponse(): void
+    {
+        $middleware = $this->createMiddleware();
+        $response = $middleware->process(new ServerRequest(), $this->createRequestHandler(new Response(200)));
+
+        $this->assertInstanceOf(ResponseInterface::class, $response);
+    }
+
+    public function testDataResponse(): void
+    {
+        $controllerRawResponse = ['id' => 1, 'name' => 'User name'];
+        $factory = $this->createDataResponseFactory();
+        $response = $factory->createResponse($controllerRawResponse);
+
+        $middleware = $this->createMiddleware();
+        $response = $middleware->process(new ServerRequest(), $this->createRequestHandler($response));
+
+        $this->assertInstanceOf(ResponseInterface::class, $response);
+        $this->assertInstanceOf(DataResponse::class, $response);
+
+        $this->assertEquals(200, $response->getStatusCode());
+        $this->assertEquals([
+            'id' => null,
+            'data' => $controllerRawResponse,
+            'error' => null,
+            'success' => true,
+        ], $response->getData());
+    }
+
+    public function testDataResponseErrorStatus(): void
+    {
+        $controllerRawResponse = ['id' => 1, 'name' => 'User name'];
+        $factory = $this->createDataResponseFactory();
+        $response = $factory->createResponse($controllerRawResponse, 400);
+
+        $middleware = $this->createMiddleware();
+        $response = $middleware->process(new ServerRequest(), $this->createRequestHandler($response));
+
+        $this->assertInstanceOf(ResponseInterface::class, $response);
+        $this->assertInstanceOf(DataResponse::class, $response);
+
+        $this->assertEquals(400, $response->getStatusCode());
+        $this->assertEquals([
+            'id' => null,
+            'data' => $controllerRawResponse,
+            'error' => null,
+            'success' => false,
+        ], $response->getData());
+    }
+
+    public function testDataResponseException(): void
+    {
+        $errorMessage = 'Test exception';
+        $middleware = $this->createMiddleware();
+        $response = $middleware->process(
+            new ServerRequest(),
+            $this->createExceptionRequestHandler(new NotFoundException($errorMessage))
+        );
+
+        $this->assertInstanceOf(ResponseInterface::class, $response);
+        $this->assertInstanceOf(DataResponse::class, $response);
+
+        $this->assertEquals(404, $response->getStatusCode());
+        $this->assertEquals([
+            'id' => null,
+            'data' => null,
+            'error' => $errorMessage,
+            'success' => false,
+        ], $response->getData());
+    }
+
+    private function createRequestHandler(ResponseInterface $response): RequestHandlerInterface
+    {
+        return new class ($response) implements RequestHandlerInterface {
+            public function __construct(
+                private ResponseInterface $response,
+            ) {
+            }
+
+            public function handle($request): ResponseInterface
+            {
+                return $this->response;
+            }
+        };
+    }
+
+    private function createExceptionRequestHandler(Throwable $exception): RequestHandlerInterface
+    {
+        return new class ($exception) implements RequestHandlerInterface {
+            public function __construct(
+                private Throwable $exception,
+            ) {
+            }
+
+            public function handle($request): ResponseInterface
+            {
+                throw $this->exception;
+            }
+        };
+    }
+
+    private function createMiddleware(): ResponseDataWrapper
+    {
+        $factory = $this->createDataResponseFactory();
+        $currentRoute = new CurrentRoute();
+        return new ResponseDataWrapper($factory, $currentRoute);
+    }
+
+    private function createDataResponseFactory(): DataResponseFactory
+    {
+        return new DataResponseFactory(
+            new ResponseFactory(),
+            new StreamFactory(),
+        );
+    }
+}
diff --git a/tests/Unit/Debug/Provider/DebugApiProviderTest.php b/tests/Unit/Debug/Provider/DebugApiProviderTest.php
new file mode 100644
index 0000000..1d26116
--- /dev/null
+++ b/tests/Unit/Debug/Provider/DebugApiProviderTest.php
@@ -0,0 +1,46 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Debug\Provider;
+
+use PHPUnit\Framework\TestCase;
+use Psr\Container\ContainerInterface;
+use Yiisoft\Router\RouteCollectorInterface;
+use Yiisoft\Yii\Debug\Api\Debug\Http\RouteCollectorWrapper;
+use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders;
+use Yiisoft\Yii\Debug\Api\Debug\Provider\DebugApiProvider;
+
+final class DebugApiProviderTest extends TestCase
+{
+    public function testExtension(): void
+    {
+        $provider = new DebugApiProvider();
+
+        $this->assertIsArray($provider->getDefinitions());
+        $this->assertIsArray($provider->getExtensions());
+        $this->assertEmpty($provider->getDefinitions());
+
+        $extensions = $provider->getExtensions();
+        $this->assertArrayHasKey(RouteCollectorInterface::class, $extensions);
+
+        $routeCollectorDecorator = $extensions[RouteCollectorInterface::class];
+        $this->assertIsCallable($routeCollectorDecorator);
+
+        $middlewares = [DebugHeaders::class];
+
+        $container = $this->createMock(ContainerInterface::class);
+        $container->expects($this->once())
+            ->method('get')
+            ->with(RouteCollectorWrapper::class)
+            ->willReturn(new RouteCollectorWrapper($middlewares));
+
+        $routeCollector = $this->createMock(RouteCollectorInterface::class);
+        $routeCollector->expects($this->once())
+            ->method('prependMiddleware')
+            ->with(...$middlewares)
+            ->willReturn($routeCollector);
+
+        $this->assertSame($routeCollector, $routeCollectorDecorator($container, $routeCollector));
+    }
+}
diff --git a/tests/Unit/Debug/Repository/CollectorRepositoryTest.php b/tests/Unit/Debug/Repository/CollectorRepositoryTest.php
new file mode 100644
index 0000000..b62153b
--- /dev/null
+++ b/tests/Unit/Debug/Repository/CollectorRepositoryTest.php
@@ -0,0 +1,100 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Debug\Repository;
+
+use PHPUnit\Framework\TestCase;
+use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepository;
+use Yiisoft\Yii\Debug\Api\Tests\Support\StubCollector;
+use Yiisoft\Yii\Debug\DebuggerIdGenerator;
+use Yiisoft\Yii\Debug\Storage\MemoryStorage;
+use Yiisoft\Yii\Debug\Storage\StorageInterface;
+
+final class CollectorRepositoryTest extends TestCase
+{
+    public function testSummary(): void
+    {
+        $idGenerator = new DebuggerIdGenerator();
+        $stubCollector = new StubCollector(['key' => 'value']);
+
+        $storage = $this->createStorage($idGenerator);
+        $repository = new CollectorRepository($storage);
+
+        $this->assertIsArray($repository->getSummary());
+        $this->assertEquals([
+            [
+                'id' => $idGenerator->getId(),
+                'collectors' => [],
+            ],
+        ], $repository->getSummary());
+
+        $storage->addCollector($stubCollector);
+
+        $this->assertIsArray($repository->getSummary());
+        $this->assertEquals([
+            [
+                'id' => $idGenerator->getId(),
+                'collectors' => [$stubCollector->getName()],
+            ],
+        ], $repository->getSummary());
+    }
+
+    public function testDetail(): void
+    {
+        $idGenerator = new DebuggerIdGenerator();
+        $stubCollector = new StubCollector(['key' => 'value']);
+
+        $storage = $this->createStorage($idGenerator);
+        $storage->addCollector($stubCollector);
+
+        $repository = new CollectorRepository($storage);
+
+        $this->assertIsArray($repository->getDetail($idGenerator->getId()));
+        $this->assertEquals([
+            $stubCollector->getName() => $stubCollector->getCollected(),
+        ], $repository->getDetail($idGenerator->getId()));
+    }
+
+    public function testDumpObject(): void
+    {
+        $idGenerator = new DebuggerIdGenerator();
+        $stubCollector = new StubCollector(['key' => 'value']);
+
+        $storage = $this->createStorage($idGenerator);
+        $storage->addCollector($stubCollector);
+
+        $repository = new CollectorRepository($storage);
+
+        $this->assertIsArray($repository->getDumpObject($idGenerator->getId()));
+        $this->assertEquals([
+            'key' => 'value',
+        ], $repository->getDumpObject($idGenerator->getId()));
+    }
+
+    public function testObject(): void
+    {
+        $idGenerator = new DebuggerIdGenerator();
+
+        $objectId = '123';
+        $stubCollector = new StubCollector([
+            'stdClass#' . $objectId => 'value',
+        ]);
+
+        $storage = $this->createStorage($idGenerator);
+        $storage->addCollector($stubCollector);
+
+        $repository = new CollectorRepository($storage);
+
+        $this->assertIsArray($repository->getObject($idGenerator->getId(), $objectId));
+        $this->assertEquals([
+            'stdClass',
+            'value',
+        ], $repository->getObject($idGenerator->getId(), $objectId));
+    }
+
+    private function createStorage(DebuggerIdGenerator $idGenerator): StorageInterface
+    {
+        return new MemoryStorage($idGenerator);
+    }
+}
diff --git a/tests/Unit/Inspector/ApplicationStateTest.php b/tests/Unit/Inspector/ApplicationStateTest.php
new file mode 100644
index 0000000..2b8aed5
--- /dev/null
+++ b/tests/Unit/Inspector/ApplicationStateTest.php
@@ -0,0 +1,19 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Inspector;
+
+use PHPUnit\Framework\TestCase;
+use Yiisoft\Yii\Debug\Api\Inspector\ApplicationState;
+
+final class ApplicationStateTest extends TestCase
+{
+    public function testStatus(): void
+    {
+        $this->assertEquals([], ApplicationState::$params);
+
+        ApplicationState::$params = ['key' => 'value'];
+        $this->assertEquals(['key' => 'value'], ApplicationState::$params);
+    }
+}
diff --git a/tests/Unit/Inspector/Command/BashCommandTest.php b/tests/Unit/Inspector/Command/BashCommandTest.php
new file mode 100644
index 0000000..5a327f7
--- /dev/null
+++ b/tests/Unit/Inspector/Command/BashCommandTest.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Inspector\Command;
+
+use PHPUnit\Framework\TestCase;
+use Yiisoft\Aliases\Aliases;
+use Yiisoft\Yii\Debug\Api\Inspector\Command\BashCommand;
+use Yiisoft\Yii\Debug\Api\Inspector\CommandResponse;
+
+final class BashCommandTest extends TestCase
+{
+    public function testSuccess(): void
+    {
+        $aliases = new Aliases([
+            '@root' => __DIR__,
+        ]);
+        $command = new BashCommand($aliases, ['echo', 'test']);
+
+        $response = $command->run();
+
+        $this->assertSame(CommandResponse::STATUS_OK, $response->getStatus());
+        $this->assertSame('test', $response->getResult());
+        $this->assertSame([], $response->getErrors());
+    }
+
+    public function testError(): void
+    {
+        $aliases = new Aliases([
+            '@root' => dirname(__DIR__, 3) . '/Support/Application',
+        ]);
+        $command = new BashCommand($aliases, ['bash', 'fail.sh', '1']);
+
+        $response = $command->run();
+
+        $this->assertSame(CommandResponse::STATUS_ERROR, $response->getStatus());
+        $this->assertSame('failed', $response->getResult());
+        $this->assertSame([], $response->getErrors());
+    }
+}
diff --git a/tests/Unit/Inspector/CommandResponseTest.php b/tests/Unit/Inspector/CommandResponseTest.php
new file mode 100644
index 0000000..68b6428
--- /dev/null
+++ b/tests/Unit/Inspector/CommandResponseTest.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Inspector;
+
+use PHPUnit\Framework\TestCase;
+use Yiisoft\Yii\Debug\Api\Inspector\CommandResponse;
+
+final class CommandResponseTest extends TestCase
+{
+    public function testStatus(): void
+    {
+        $response = new CommandResponse(CommandResponse::STATUS_OK, 'result', ['errors']);
+
+        $this->assertSame(CommandResponse::STATUS_OK, $response->getStatus());
+        $this->assertSame('result', $response->getResult());
+        $this->assertSame(['errors'], $response->getErrors());
+    }
+}
diff --git a/tests/Inspector/Database/DbSchemaProviderTest.php b/tests/Unit/Inspector/Database/DbSchemaProviderTest.php
similarity index 98%
rename from tests/Inspector/Database/DbSchemaProviderTest.php
rename to tests/Unit/Inspector/Database/DbSchemaProviderTest.php
index 0584e09..5a00506 100644
--- a/tests/Inspector/Database/DbSchemaProviderTest.php
+++ b/tests/Unit/Inspector/Database/DbSchemaProviderTest.php
@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace Yiisoft\Yii\Debug\Api\Tests\Inspector\Database;
+namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Inspector\Database;
 
 use PHPUnit\Framework\TestCase;
 use Yiisoft\Cache\NullCache;