Middleware
Middleware wraps a request and the next handler. The PSR-15 contract can terminate processing with its own response or modify the next handler’s response.
A PSR-15 middleware
AppHeaderMiddleware implements PSR-15 process(). It delegates the request through handle(), then adds X-App to the returned PSR-7 response. withHeader() returns the modified response copy to the runtime.
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
final class AppHeaderMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler,
): ResponseInterface {
return $handler->handle($request)->withHeader('X-App', 'example');
}
}Attaching to a route
Routing.php attaches AppHeaderMiddleware only to the account route. The container resolves it after the route matches; it wraps AccountController::show() and adds the header on the response path. Other routes are unaffected.
<?php
declare(strict_types=1);
use App\Controllers\AccountController;
use App\Http\Middleware\AppHeaderMiddleware;
use Lemonade\Framework\Routing\ControllerAction;
$router
->getNamed(
'account',
'/account',
ControllerAction::for(AccountController::class, 'show'),
)
->middleware(AppHeaderMiddleware::class);Stopping the pipeline
RequireRequestId reads X-Request-Id from the PSR request. If absent, it returns its own JSON 400 response without calling the handler; otherwise the pipeline continues. Header presence alone is not authentication.
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Lemonade\Framework\Http\Response\Responses;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
final readonly class RequireRequestId implements MiddlewareInterface
{
public function __construct(private Responses $responses) {}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler,
): ResponseInterface {
if ($request->getHeaderLine('X-Request-Id') === '') {
return $this->responses->json(['error' => 'Missing request ID'], 400);
}
return $handler->handle($request);
}
}