PSR-15 middleware, and the interface it standardised

Every framework had middleware and none of them agreed on the signature, so a piece of middleware was written once per framework despite doing the same thing.

final class RequestId implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        $id = $request->getHeaderLine('X-Request-Id') ?: bin2hex(random_bytes(8));

        return $handler->handle($request->withAttribute('request_id', $id))
            ->withHeader('X-Request-Id', $id);
    }
}

The handler being an object rather than a callable is the part that took years to agree on, and it is what makes the chain inspectable. The immutability of PSR-7 messages is the tax: every with call returns a new object, so forgetting to use the return value is the single most common mistake and it fails silently. Adoption in 2018 is real but partial — Laravel has its own shape and shows no sign of changing it.