--- 
canonical: 'https://mwop.net/blog/2018-01-23-psr-15.html'
title: PSR-15
author: "[Matthew Weier O'Phinney](https://mwop.net)"
created: '2018-01-23T14:05:00-06:00'
updated: '2018-01-23T14:05:00-06:00'
tags:
  - php
  - programming
  - psr-15
  - psr-7

---
Yesterday, following a unanimous vote from its Core Committee, 
[PHP-FIG](http://www.php-fig.org/) formally accepted the proposed
[PSR-15, HTTP Server Handlers](https://github.com/php-fig/fig-standards/tree/master/accepted/PSR-15-request-handlers.md)
standard.

This new standard defines interfaces for _request handlers_ and _middleware_.
These have enormous potential impact on the PHP ecosystem, as they provide
standard mechanisms for writing HTTP-facing, server-side applications.
Essentially, they pave the way for developers to create re-usable web components
that will work in any application that works with PSR-15 middleware or request
handlers!





> ### Caveat
> 
> I acted as sponsor on PSR-15, and as final arbiter of changes during the review
> period.

## Background

PSR-15 was started by [Woody Gilk](http://shadowhand.me), who has acted in the
role of Editor for its duration. The original intent was to ratify a middleware
standard, and it was initially thought that it would be a quick ratification of
a pattern that was already in wide use:

```php
function (
    ServerRequestInterface $request,
    ResponseInterface $response,
    callable $next
) : ResponseInterface
```

where `$next` should implement the following signature:

```php
function (
    ServerRequestInterface $request,
    ResponseInterface $response
) : ResponseInterface
```

> ### "Double Pass"
>
> The above pattern has been dubbed "double pass" middleware, for the fact that
> it passes _two_ instances to the collaborator to _pass_ to the next layer.

However, a number of critiques of this existing practice started to arise almost
immediately, with [one from Anthony Ferrara](https://blog.ircmaxell.com/2016/05/all-about-middleware.html)
holding particular weight. The primary problems noted were:

- Passing the response from layer to layer can lead to issues where an outer
  layer makes a change to the response it passes to an inner layer, expecting it
  to propagate back out, but an inner layer returns a different response entirely.
  Essentially, the pattern promotes problematic practices. If middleware needs
  to operate on a response, it should operate on the response returned by
  another layer.

- Typehinting `$next` as callable means there's no way to ensure that the
  callable is actually capable of accepting the arguments passed to it. In other
  words, it's not type safe.

After debate within the working group, the next iteration proposed the
following (some details differ, but basic interactions are the same):

```php
interface DelegateInterface
{
    public function process(ServerRequestInterface $request) : ResponseInterface;
}

interface MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        DelegateInterface $delegate
    ) : ResponseInterface;
}
```

This largely solved the problems highlighted above. However, a few more details
came up as different teams developed implementations.

First, many noted that they felt defining the same method name prevented
polymorphism. A common use case was to define a "request handler" that could
be called and which would in turn _process_ itself. So, we updated the
interfaces as follows:

```php
interface RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request) : ResponseInterface;
}

interface MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ) : ResponseInterface;
}
```

Second, once that change was done, a number of others noted that the request
handler could be useful in and of itself. For example, when creating a simple
site, you could marshal a server request, pass it to a handler, and emit the
response returned; middleware might not be necessary in this case. Another use
case is for the final, internal end points of a middleware application: instead
of implementing these as middleware, one could implement them as request
handlers instead, as they do not operate on the results of the handler.

As a result, we made the change to ship the two interfaces _as separate
packages_, with the package containing the `MiddlewareInterface` depending on
the package defining the `RequestHandlerInterface`.

Finally, over the close to two years that this specification was being
developed, PHP 7 gained in maturity, with 7.1 and 7.2 releases. We decided to
pin the specification to PHP 7 or greater, and formally adopted return type
hints within it.

While work on the specification was in progress, each iteration of the
interfaces was published within the github organization
[http-interop](https://github.com/http-interop), with packages matching whatever
the current specification detailed (http-middleware, then
http-server-middleware, and, eventually, adding http-server-handler). These
packages also used `Interop\Http` as the top-level namespace. Members of
the working group, as well as other interested parties, would pin their
offerings to specific iterations.

The final packages are now owned by the PHP-FIG group, however, and use the
`Psr` top-level namespace.

## The Interfaces

That brings us to the final standard:

- [PSR-15](https://github.com/php-fig/fig-standards/tree/master/accepted/PSR-15-request-handlers.md)
- [PSR-15 Meta Document](https://github.com/php-fig/fig-standards/tree/master/accepted/PSR-15-request-handlers-meta.md)
  (which covers the _whys_ behind the specification)

[psr/http-server-handler](https://github.com/php-fig/http-server-handler)
provides the following interface:

```php
namespace Psr\Http\Server;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

interface RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request) : ResponseInterface;
}
```

[psr/http-server-middleware](https://github.com/php-fig/http-server-middleware)
provides the following interface:

```php
namespace Psr\Http\Server;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

interface MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ) : ResponseInterface;
}
```

Both packages depend on [PSR-7](http://www.php-fig.org/psr/psr-7/) as they
typehint against the HTTP message interfaces that package defines. The
http-server-middleware package depends on the http-server-handler package.

## How to write re-usable middleware

Most middleware dispatchers available currently (and there are a LOT of them, as
it turns out!) allow you to compose middleware in such a way that none of it
needs to know how or what is composing it. This is A Good Thing™. It allows you
to write middleware that is de-coupled from the context in which it is used.

But how do you do that?

In the meta document for the specification, we [suggest the
following](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-15-request-handlers-meta.md#reusable-middleware-examples):

- Test the request for required pre-conditions, if any. If it does not
  satisfy any, use a composed _response prototype_ or _response factory_ to
  generate and return a response.

- If pre-conditions are met, delegate creation of the response to the provided
  handler, optionally providing a "new" request (PSR-7 requests are immutable,
  so this means calling one of its `with*()` methods, which return new
  instances).

- Either pass the response back from the handler verbatim, or return a new
  response by manipulating the one returned (again, via one of the `with*()`
  methods).

The first point is probably the most important here: do not directly instantiate
a response in your middleware, but instead use a _prototype_ or a _factory_ that
is provided during instantiation. This allows you to de-couple your middleware
from the PSR-7 implementation used by the application.

In practice, that might look something like this:

```php
class CheckOriginMiddleware implements MiddlewareInterface
{
    private $acceptedOrigins;
    private $responsePrototype;

    public function __construct(array $acceptedOrigins, ResponseInterface $responsePrototype)
    {
        $this->acceptedOrigins = $acceptedOrigins;
        $this->responsePrototype = $responsePrototype;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
    {
        $origin = $request->getHeaderLine('origin');
        if (! in_array($origin, $this->acceptedOrigins, true)) {
            return $this->responsePrototype
                ->withStatus(401)
                ->withHeader('X-Invalid-Origin', $origin);
        }

        $response = $handler->handle($request);

        return $response->withHeader('X-Origin', $origin);
    }
}
```

A few things to note about this middleware:

- It accepts dependencies via its constructor. This practice allows us to easily
  test the middleware, and defines what it needs in order to do its work.

- The response prototype ensures we are de-coupled from the PSR-7
  implementation. I can pass a Diactoros response, a Guzzle response, a Slim
  response, or any other implementation. As a result, consumers of this
  middleware will not need to potentially install another PSR-7 implementation.

- The middleware has no idea where it will be used, or what stack it will be used
  in. It simply operates on the request and the handler provided when
  `process()` is called.

How might I consume such middleware?

In [Expressive](https://docs.zendframework.com/zend-expressive/)), I might do
any one of the following:

```php
// Pipe it as a service to pull from the DI container:
$app->pipe(CheckOriginMiddleware::class);

// Use it within a route-specific pipeline:
$app->post('/api/foo', [
    CheckOriginMiddleware::class,
    FooMiddleware::class,
]);
```

In [northwoods/broker](https://github.com/northwoods/broker) (maintained by
Woody Gilk, the PSR-15 editor), it looks like this:

```php
$broker->always([CheckOriginMiddleware::class]);
```

In [middlewares/utils Dispatcher](https://github.com/middlewares/utils), you'd
do this:

```php
$dispatcher = new Dispatcher([
    /* ... */
    new CheckOriginMiddleware($acceptedOrigins, $responsePrototype),
    /* ... */
]);
```

With any one of these solutions, if your middleware is executed, it will act
exactly the same; _how_ it is composed doesn't matter, as the way it operates is
only dependent on the request and handler passed to the middleware during
`process()`.

## What about request handlers?

Most of the libraries I've looked at at this time define handlers in one of two
ways:

- As a middleware dispatcher. In this particular case, each middleware is
  processed until one returns a response. If the last one processed calls on the
  handler again, then a canned response is returned, an exception is thrown, or
  the next scenario comes into play:

- As a "final" handler to pass to the middleware dispatcher. In other words, if
  the last middleware processed _also_ calls on its handler, this "fallback" or
  "final" handler will be what's invoked. This will typically return a 404
  response or a 500 response, depending on the implementation.

One other possibility that's been floated by several is for use with _routing
middleware_. In this case, when routing middleware matches a request, it would
then call on a request handler mapped to that request.

## Notes for implementors

PSR-15 is accepted; let's make all the things PSR-15!

But have some patience! While a number of projects have been working with
various iterations of the http-interop packages, and may need some time to
update to the final PSR-15 specification.

For example, we've been tracking various iterations of http-interop in both
Stratigility and Expressive, but updating to the PSR-15 specification requires
backwards-incompatible changes, necessitating a new 3.0 version &mdash; which
need a few more weeks to drop. Slim [also has a patch submitted with PSR-15 support](https://github.com/slimphp/Slim/pull/2379),
which would likely not drop until an upcoming 4.0 release.

As such, have patience with library and framework maintainers, and help test
releases for them.

Additionally, consider tracking and testing the [proposed PSR-17
specification](https://github.com/php-fig/fig-standards/tree/de189e864044ce726f7e75b7d17ac98ea049f45c/proposed/http-factory).
This proposal will standardize PSR-7 _factories_, which will provide a standard
way for middleware to generate, in particular, responses to return. Instead of
composing a response prototype, you would compose a factory. Why is this easier?
Well, in cases where you may also want to address the response _body_, which is
a `Psr\Http\Message\StreamInterface` instance, it allows you to create new
instances of those as well. Since streams cannot be immutable (due to language
limitations), any time you write to a stream, you could be appending existing
content, which means middleware that writes to the response prototype body
generally needs to also compose a _stream_ prototype. What if you could compose
a single factory instead?

## Closing thoughts

When I started work on PSR-7 originally, _it was because I wanted a standard
middleware interface for PHP_. I'd been playing with Node, and, more
specifically, Sencha Connect and ExpressJS. The middleware ecosystem in Node was
and continues to be tremendous. The reason it exists is because of two factors:

- Accepted, standard middleware signature. Even though JS doesn't provide
  interfaces, and there is no userland standards body, a consensus signature
  emerged, and everyone used it. These were possible because of:

- Built-in HTTP message abstractions in the Node core library.

If I wanted standard middleware in PHP, we first needed standard HTTP messages,
which PSR-7 accomplished. That could have been the end of it, as many libraries
started using the same middleware signatures; however, we soon had at least two,
and possibly as many as a half-dozen different approaches. Thankfully, Woody
stepped up to the task and proposed what became PSR-15; further, he, and the
other members of the working group, had the patience and stamina to see it to
acceptance (though I know there were several times he and others almost threw
the towel in!).

With PSR-15 accepted, we are a step closer to something I have long envisioned: 
a possibility for PHP developers to no longer work within monolithic MVC
frameworks, but instead compose applications out of commodity, reusable
middleware.
