yiisoft/yii-http
A lightweight HTTP layer for Yii, offering request/response handling, middleware support, and PSR standards integration. It provides clean abstractions for building structured, testable web endpoints that fit Yii's DI and configuration conventions.
This package is the thin "application" layer of a Yii3 HTTP stack: a PSR-15 RequestHandlerInterface implementation that wraps your request handler in a middleware dispatcher and a fallback handler. In day-to-day work you almost never instantiate it directly — you configure it and let a runner (yiisoft/yii-runner-http) call ->handle($request).
Minimal steps:
composer create-project yiisoft/app or add yiisoft/yii-http plus yiisoft/yii-runner-http (and a router, e.g. yiisoft/router-fastroute).config/web/application.php (or config/application.php in older templates). This is the single file that matters. The yiisoft/yii-http group defines three keys:
middleware — the ordered PSR-15 pipeline,requestHandler — the terminal handler (typically the router),fallbackHandler — invoked when the main handler throws (404s, errors).config/di.php / config/params.php of the package itself (vendor/yiisoft/yii-http/config/) rather than trusting blog posts — the parameter shape has shifted across Yii3 releases.First use case: add one middleware and see it run. For example, append a trivial logger to the middleware array:
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface};
use Psr\Http\Server\{MiddlewareInterface, RequestHandlerInterface};
final class RequestLogger implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
error_log($request->getMethod() . ' ' . $request->getUri()->getPath());
return $handler->handle($request);
}
}
Then hit the app. If the log line appears, you understand the pipeline and everything else is just configuration.
Middleware ordering is the whole game. The array is applied outermost-first: index 0 wraps everything, the last element is closest to the request handler. The conventional Yii3 order is error handler → request catcher → router → (per-route middleware) → handler. Put yiisoft/error-handler at or near the top so it can convert exceptions into responses before the application's own fallback logic engages.
Terminal handlers for testing. Application is just a request handler, so you can test the whole pipeline without a web server:
$app = $container->get(Application::class);
$request = (new ServerRequestFactory())->createServerRequest('GET', '/posts/1');
$response = $app->handle($request);
$this->assertSame(200, $response->getStatusCode());
This is the single most useful pattern — it makes the HTTP layer unit-testable and is why the package exists as a separate abstraction.
Custom request handlers. Anything implementing RequestHandlerInterface can be the requestHandler. For a microservice or health endpoint you can skip the router entirely and return a fixed response. For a fallback, implement a 404/JSON error responder that respects Accept headers.
Per-route middleware. Register cross-cutting concerns (auth, CSRF, rate limiting) globally, and route-specific ones through the router's middleware support so they don't run for every static asset or health check.
Events for observability. Application dispatches ApplicationStartup, ApplicationShutdown, and AfterEmit (the latter around emitting in a runner). Attach a PSR-14 listener for timing/metrics rather than sprinkling microtime() in middleware.
Composition over inheritance. Everything here is interface-driven; swap the dispatcher (yiisoft/middleware-dispatcher), the fallback, or the router independently. Prefer constructor injection of LoggerInterface, EventDispatcherInterface, and response factories — don't reach for globals.
ServerRequestInterface. If you call handle() outside a runner you must build it yourself (yiisoft/http message factories or nyholm/psr7), and you must also emit the response.fallbackHandler to something that rethrows or logs the throwable — otherwise the original exception is lost.requestHandler vs fallbackHandler confusion. They are different roles: the first is the normal terminal, the second is the recovery path. Don't put routing logic in the fallback.$this; pass it through method arguments and request attributes.ClassName::class, [ClassName::class, 'method'], definitions with __class/__construct, or closures. If a middleware silently doesn't run, the definition probably produced nothing — check config/di.php in the package for the normalized form.ResponseInterface return. Returning null, void, or a string will blow up deep in the dispatcher. Type your process() signature and let static analysis catch it.NotFoundException from yiisoft/router propagates to the application and lands on the fallback handler. If you want JSON 404s for API routes and HTML for the rest, that decision belongs in the fallback handler based on the request's Accept header — not in each route.Application constructor (dispatcher, request handler, fallback, event dispatcher) is the place to swap behavior. Override the DI definition rather than subclassing — Application is final in most releases.yiisoft/*). Read vendor/yiisoft/yii-http/src/Application.php end to end — it's a few dozen lines and will answer 90% of questions faster than searching docs.How can I help you explore Laravel packages today?