Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion proposed/http-middleware/middleware-meta.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ provides a number of benefits:
## 3.1 Goals

* Create a middleware interface that uses HTTP Messages.
* Provide a suggested interface for middleware stack containers.
* Ensure that middleware will not be tied to a specific implementation of HTTP Messages.
* Implement a middleware signature that is based on best practices.

## 3.2 Non-Goals

* Attempting to define the mechanism by which middleware is managed or dispatched.
* Attempting to define the mechanism by which HTTP responses are created.

4. Approaches
-------------
Expand Down
201 changes: 151 additions & 50 deletions proposed/http-middleware/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,102 +2,203 @@ HTTP Middleware
===============

This document describes a common standard for HTTP middleware components using
[PSR-7][psr7] compliant HTTP messages.
HTTP Messages defined by [PSR-7](http://www.php-fig.org/psr/psr-7/).

HTTP middleware has been an important concept on other web development platforms
for a good number of years, and since the inception of PSR-7 has been growing
increasingly popular in the PHP world.
for a good number of years, and since the introduction of a formal HTTP Messages
standard has been growing increasingly popular with web frameworks.

An informal (de-facto) standard for the signature of middleware components is
already widely in use, and this PSR serves to provide a formal definition in
the form of a common standard interface for middleware components.

The interface described in this document is an abstraction of an individual
middleware component.
The interfaces described in this document are abstractions for HTTP middleware
and the containers that are used to process HTTP requests.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in [RFC 2119][rfc2119].
interpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119).

### References

[psr7]: http://www.php-fig.org/psr/psr-7/
[rfc2119]: http://tools.ietf.org/html/rfc2119
- [RFC 2119](http://tools.ietf.org/html/rfc2119)
- [PSR-7](http://www.php-fig.org/psr/psr-7/)

## 1. Specification

An HTTP middleware component is an individual component participating, together
with other middleware components, in the processing of an incoming HTTP Request
and the creation of a resulting HTTP Response, as defined by PSR-7.

Middleware components MUST implement this interface.
Middleware consumers such as frameworks and middleware stack containers MUST
use a type declaration against one of the middleware interfaces:

Middleware consumers (e.g. frameworks and middleware stacks) MUST type-hint any
method accepting middleware components as arguments formally as `callable`, and
informally as `Psr\Http\Middleware\MiddlewareInterface`, e.g. using php-doc tags:
- `Psr\Http\Middleware\MiddlewareInterface` if both client and server middleware are supported
- `Psr\Http\Middleware\ClientMiddlewareInterface` if only client middleware is supported
- `Psr\Http\Middleware\ServerMiddlewareInterface` if only server middleware is supported

```php
/**
* @param MiddlewareInterface $middleware
*/
public function push(callable $middleware)
{
// ...
}
```
Generally consumers SHOULD type hint against `MiddlewareInterface` unless the
consumer only processes client requests.

### 1.1 Containers

An HTTP middleware container is an object that holds multiple middleware
components that can be used to process one or more requests in sequence.

The middleware container MUST pass the request and a dispatcher to each
middleware component that it executes. The dispatcher MUST be able to execute
the next available middleware or if no more middleware is available, create a
default response.

### 1.2 Generating Responses

It is RECOMMENDED that any middleware that needs to generate a response will
use HTTP Factories as defined in [PSR-17](http://www.php-fig.org/psr/psr-7/),
in order to prevent dependence on a specific HTTP message implementation.

## 2. Interfaces

The following interface MUST be implemented by any compatible middleware component.
### 2.1 Psr\Http\Middleware\MiddlewareInterface

The following interface is only used for type hints that accept middleware components
and MUST NOT be implemented directly.

```php
namespace Psr\Http\Middleware;

interface MiddlewareInterface {}
```

### 2.3 Psr\Http\Middleware\ClientMiddlewareInterface

The following interface MUST be implemented by compatible client middleware components.

```php
namespace Psr\Http\Middleware;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface MiddlewareInterface
interface ClientMiddlewareInterface extends MiddlewareInterface
{
/**
* Process a request and return a response.
* Handle a client request and return a response.
*
* Takes the incoming request and optionally modifies it before delegating
* to the next handler to get a response. May modify the response before
* ultimately returning it.
* to the next frame to get a response.
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param callable $next delegate function that will dispatch the next middleware component:
* function (RequestInterface $request, ResponseInterface $response): ResponseInterface
* @param FrameInterface $next
*
* @return ResponseInterface
*/
public function __invoke(
public function handle(
RequestInterface $request,
ResponseInterface $response,
callable $next
FrameInterface $next
);
}
```

Note that a dispatcher MUST NOT pass an actual middleware component as the
callable `$next` - this callable is not the actual middleware component, but
a *delegate* function to dispatch the next middleware component, generated by
the dispatcher. A simple implementation MAY be defined as:
### 2.4 Psr\Http\Middleware\ServerMiddlewareInterface

The following interface MUST be implemented by compatible server middleware components.

```php
namespace Psr\Http\Middleware;

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

interface ServerMiddlewareInterface extends MiddlewareInterface
{
/**
* Handle a server request and return a response.
*
* Takes the incoming request and optionally modifies it before delegating
* to the next frame to get a response.
*
* @param ServerRequestInterface $request
* @param FrameInterface $frame
*
* @return ResponseInterface
*/
public function handle(
ServerRequestInterface $request,
FrameInterface $frame
);
}
```
public function __invoke(RequestInterface $request, ResponseInterface $response)

Note that the only difference between server and client middleware is that server
middleware must be passed a server request for processing.

### 2.5 Psr\Http\Middleware\FrameInterface

The following interface MUST be implemented by middleware stack frames.

```php
namespace Psr\Http\Middleware;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface FrameInterface
{
$middleware = $this->getNextMiddleware();
return $middleware($request, $response, $this);
/**
* Dispatch the next available middleware and return the response.
*
* @param RequestInterface $request
*
* @return ResponseInterface
*/
public function next(RequestInterface $request);
}
```

### 2.2 Server vs Client Requests
### 2.6 Psr\Http\Middleware\StackInterface

The following interface MAY be implemented by middleware stack containers.

```php
namespace Psr\Http\Middleware;

Some middleware components may require the additional methods defined by
`ServerRequestInterface`, such as reading cookies or setting attributes.
In this case, the middleware MUST check the type of the request before
using these methods.
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

If the incorrect request type is used components SHOULD throw an
`InvalidArgumentException` or an extension of it.
interface StackInterface
{
/**
* Return an instance with the specified middleware added to the stack.
*
* This method MUST be implemented in such a way as to retain the
* immutability of the stack, and MUST return an instance that contains
* the specified middleware.
*
* @param MiddlewareInterface $middleware
*
* @return self
*/
public function withMiddleware(MiddlewareInterface $middleware);

/**
* Return an instance without the specified middleware.
*
* This method MUST be implemented in such a way as to retain the
* immutability of the stack, and MUST return an instance that does not
* contain the specified middleware.
*
* @param MiddlewareInterface $middleware
*
* @return self
*/
public function withoutMiddleware(MiddlewareInterface $middleware);

/**
* Process the request through middleware and return the response.
*
* This method MUST be implemented in such a way as to allow the same
* stack to be reused for processing multiple requests in sequence.
*
* @param RequestInterface $request
*
* @return ResponseInterface
*/
public function process(RequestInterface $request);
}
```