gmarche/vendor/http-interop/http-middleware
nox a0fd572948 Premiere mouture application - Suppression fichiers inutiles 2019-09-18 00:31:59 +02:00
..
src Premiere mouture application - Suppression fichiers inutiles 2019-09-18 00:31:59 +02:00
.pullapprove.yml Premiere mouture application - Suppression fichiers inutiles 2019-09-18 00:31:59 +02:00
LICENSE Premiere mouture application - Suppression fichiers inutiles 2019-09-18 00:31:59 +02:00
README.md Premiere mouture application - Suppression fichiers inutiles 2019-09-18 00:31:59 +02:00
composer.json Premiere mouture application - Suppression fichiers inutiles 2019-09-18 00:31:59 +02:00

README.md

HTTP Server Middleware

  1. Summary

The purpose of this PSR is to provide an interface that defines the formal method signature for HTTP Server Middleware that is compatible with HTTP Messages, as defined in PSR-7.

  1. Why Bother?

The HTTP Messages specification does not contain any reference to HTTP Middleware.

The design pattern used by middleware has existed for many years as the pipeline pattern, or more specifically, "linear pipeline processing". The general concept of reusable middleware was popularized within PHP by StackPHP. Since the release of the HTTP Messages standard, a number of frameworks have adopted middleware that use HTTP Message interfaces.

Agreeing on a formal server middleware interface eliminates several problems and provides a number of benefits:

  • Provides a formal standard for middleware developers to commit to.
  • Eliminates duplication of similar interfaces defined by various frameworks.
  • Avoids minor discrepancies in method signatures.
  • Enables any middleware component to run in any compatible framework.
  1. Scope

3.1 Goals

  • Create a middleware interface that uses HTTP Messages.
  • Ensure that middleware will not be coupled to a specific implementation of HTTP Messages.
  • Implement a middleware signature that is based on best practices.

3.2 Non-Goals

  • Attempting to define how middleware is dispatched.
  • Attempting to define interfaces for client/asynchronous middleware.
  • Attempting to define the mechanism by which HTTP responses are created.
  1. Approaches

There are currently two common approaches to server middleware that use HTTP Messages.

4.1 Double Pass

The signature used by most middleware implementations has been mostly the same and is based on Express middleware, which is defined as:

fn(request, response, next): response

Based on the middleware implementations already used by frameworks that have adopted this signature, the following commonalities are observed:

  • The middleware is defined as a callable.
  • The middleware is passed 3 arguments during invocation:
    1. A ServerRequestInterface implementation.
    2. A ResponseInterface implementation.
    3. A callable that receives the request and response to delegate the next middleware.

A significant number of projects provide and/or use exactly the same interface. This approach is often referred to as "double pass" in reference to both the request and response being passed to the middleware.

4.1.1 Projects Using Double Pass

4.1.2 Middleware Implementing Double Pass

The primary downside of this interface is that the while the interface itself is a callable, there is currently no way to type hint a closure in a similar way.

4.2 Single Pass (Lambda)

The other approach to middleware is much closer to StackPHP style and is defined as:

fn(request, frame): response

Middleware taking this approach generally has the following commonalities:

  • The middleware is defined with a specific interface with a method that takes the request for processing.
  • The middleware is passed 2 arguments during invocation:
    1. An object that represents an HTTP request.
    2. A delegate that receives the request to dispatch next middleware in the pipeline.

In this form, middleware has no access to a response until one is generated by innermost middleware. Middleware can then modify the response before returning back up the stack.

This approach is often referred to as "single pass" or "lambda" in reference to only the request being passed to the middleware.

4.2.1 Projects Using Single Pass

There are fewer examples of this approach within projects using HTTP Messages, with one notable exception.

Guzzle middleware is focused on outgoing (client) requests and uses this signature:

function(RequestInterface $request, array $options): ResponseInterface

4.2.2 Additional Projects Using Single Pass

There are also significant projects that predate HTTP Messages using this approach.

StackPHP is based on Symfony HttpKernel and supports middleware with this signature:

handle(Request $request, $type, $catch): Response

Note: While Stack has multiple arguments, a response object is not included.

Laravel middleware uses Symfony components and supports middleware with this signature:

function handle(Request $request, callable $next): Response

4.3 Comparison of Approaches

The single pass approach to middleware has been well established in the PHP community for many years. This is most evident with the large number of packages that are based around StackPHP.

The double pass approach is much newer but has been almost universally used by early adopters of HTTP Messages.

4.4 Chosen Approach

Despite the nearly universal adoption of the double-pass approach there are significant issues regarding implementation.

The most severe is that passing an empty response has no guarantees that the response is in a usable state. This is further exacerbated by the fact that a middleware may modify the response before passing it for further dispatching.

Further compounding the problem is that there is no way to ensure that the response body has not been written to, which can lead to incomplete output or error responses being sent with cache headers attached. It is also possible to end up with corrupted body content when writing over existing body content if the new content is shorter than the original. The most effective way to resolve these issues is to always provide a fresh stream when modifying the body of a message.

Some have argued that passing the response helps ensure dependency inversion. While it is true that it helps avoid depending on a specific implementation of HTTP messages, the problem can also be resolved by injecting factories into the middleware to create HTTP message objects, or by injecting empty message instances. With the creation of HTTP Factories in PSR-17, a standard approach to handling dependency inversion is possible.

A more subjective, but also important, concern is that existing double-pass middleware typically uses the callable type hint to refer to middleware. This makes strict typing impossible, as there is no assurance that the callable being passed implements a middleware signature, which reduces runtime safety.

Due to these significant issues the lambda approach has been choosen for this proposal.

  1. Design Decisions

5.1 Middleware Design

The MiddlewareInterface defines a single method that accepts a server request and a delegate and must return a response. The middleware may:

  • Evolve the request before passing it to the delegate to execute the next available middleware.
  • Evolve the response received from the delegate before returning it.
  • Create and return a response without passing it to the delegate, thereby preventing any further middleware from executing.

Why doesn't middleware use __invoke?

Doing so would conflict with existing middleware that implements the double-pass approach and may want to implement the middleware interface.

In addition, classes that define __invoke can be type hinted as callable, which results in less strict typing. This is generally undesirable, especially when the __invoke method uses strict typing.

Why is a server request required?

To make it clear that the middleware can only be used in a synchronous, server side context.

While not all middleware will need to use the additional methods defined by the server request interface, external requests are typically handled asynchronously and would need to return a promise of a response. (This is primarily due to the fact that multiple requests can be made in parallel and processed as they are returned.) It is outside the scope of this proposal to address the needs of asynchronous request/response life cycle.

Attempting to define client middleware would be premature at this point. Any future proposal that is focused on client side request processing should have the opportunity to define a standard that is specific to the nature of asynchronous middleware.

See "client vs server side middleware" in relevant links for additional information.

5.2 Delegate Design

The DelegateInterface defines a single method that accepts a request and returns a response. The delegate interface must be implemented by any middleware dispatcher that uses middleware implementing MiddlewareInterface.

Why isn't the delegate a callable?

Using an interface type hint improves runtime safety and IDE support.

See "discussion of FrameInterface" in relevant links for additional information.

Why does the delegate conflict with middleware?

Both the middleware and delegate interface define a process method to prevent misuse of middleware as delegates.

The implementation of delegate should be defined within middleware dispatching systems.

  1. People

6.1 Editor(s)

6.2 Sponsors

6.3 Contributors

  1. Votes

  1. Relevant Links

Note: Order descending chronologically.

  1. Errata

...