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.