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.

app/Http/Middleware/AppHeaderMiddleware.php
<?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.

app/Config/Routing.php
<?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.

app/Http/Middleware/RequireRequestId.php
<?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);
    }
}
Related documentationRead the Middleware chapter in the documentation for more detail.

← All examples