[RFC] HTTP handler interface

262 views
Skip to first unread message

Giulio De Donato

unread,
Sep 9, 2015, 7:40:38 AM9/9/15
to PHP Framework Interoperability Group
Hi all,

Working on a web language is necessary
have a standard for the request/response handling,
and after the PSR7 this standard appears as a normal evolution.

Honestly I also wonder why it has not yet been defined (I found nothing searching on old threads).

On the web I found many implementations, 
we everybody know the very used SymfonyKernelInterface but it does not fit well with the new PSR7 response,
personally working with Go-Lang I found their interface very effective.

Here a list of all interface I found/used:

PHP-Symfony:

public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);


Golang: (call it 'handler'  with Response and then Request)

  type HandlerFunc func(ResponseWriter, *Request)  


Node http.server

  function (request, response) { }

Other implementations 
 -guzzle has its own implementation ref. https://github.com/guzzle/guzzle
  - zend-stratigility:   public function __invoke(Request $request, Response $response, callable $out = null);
    ref. https://mwop.net/blog/2015-01-08-on-http-middleware-and-psr-7.html
 

The goal would be define a standard interface for the http handling, 
something like:

  public function handle(ServerRequestInterface $request, ResponseInterface $response);
  
  ref: https://github.com/liuggio/http/ 

hope to start a discussion with comments on this,

Thanks a lot


giulio aka liuggio

Alessandro Nadalin

unread,
Sep 9, 2015, 7:47:21 AM9/9/15
to php...@googlegroups.com
Would love to see something as simple as node, where you have req / res only. 

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/710eaff2-3bd5-4927-9b13-80b91f6e81ba%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Woody Gilk

unread,
Sep 9, 2015, 10:40:10 AM9/9/15
to php...@googlegroups.com
Throwing another one into the mix, Paul Jones has a similar "framework" in Relay http://relayphp.com/

--

Matthew Weier O'Phinney

unread,
Sep 10, 2015, 1:04:29 PM9/10/15
to php...@googlegroups.com
On Wed, Sep 9, 2015 at 6:40 AM, Giulio De Donato <liu...@gmail.com> wrote:
> Working on a web language is necessary
> have a standard for the request/response handling,
> and after the PSR7 this standard appears as a normal evolution.

The concept is properly termed "middleware".

> Honestly I also wonder why it has not yet been defined (I found nothing
> searching on old threads).

It hasn't been defined, as it was out of scope for PSR-7. It's
essentially the same reason as why HTTP client interface
specifications do not exist; we needed the prerequisites done first
(HTTP Message interfaces).

I've been trying to find time to catalog the various implementations
as a precursor to standardization, but have found myself without much
time to do so. I'll provide my thoughts below.
There's more.

## WSGI: function (environ, start_response) : stream

With WSGI, "environ" is a struct that contains essentially the same
keys as defined in the CGI specification, as well as a few that are
"aggregates" for things like URIs, headers, etc. start_response is a
callback that accepts the status code and response headers. The body
is sent by returning a stream.

Simplified, it's essentially: function (Request, Response) : Response

WSGI was the original web middleware interface, and has influenced
every other since.

## Rack: function (environment) : []

Rack's "environment" is similar to WSGI, and also contains a number of
rack-specific variables (all referenced by `rack.*`). The function is
expected to return an array with exactly three values, the status,
headers, and body (which may be a stream).

Simplified, it's essentially: function (Request) : Response

Side note at this time: the above two (WSGI and Rack) essentially
require "onion"-style architectures for middleware. In other words, if
you want to execute or delegate to additional middleware, you must
compose that middleware internally in layers.

## Node

As you noted, the basic concept is:

- function (Request, Response) : Response

However, the predominant pattern I've seen in Node is the one provided
by Connect and ExpressJS, which is:

- function (Request, Response, next) : Response

where next is a callable that will execute the next handler in the
list. Typically, if a handler returns a function, execution ends. The
handler called at the application level also receives a callable "out"
which is executed if no Response is returned by any handlers.

Having the Response in the signature means that middleware does not
need to depend on concrete implementations internally, but can instead
operate on the response provided, reducing dependencies in some
situations.

This approach enables execution of FIFO lists of middleware, as well
as onion-style architectures.

This pattern is also used in PHP by Stratigility (and thus
Expressive), Slim 3, and Relay.

## Lumen: function (Request) : Response

Laravel's Lumen framework uses a purely functional paradigm: you
provide a request, and you're expected to return a response. This
means that any middleware that will return a response (vs returning
the result of composed middleware) has a dependency on a concrete
response implementation. It can only do onion-style architectures.

## StackPHP

Stack uses the HttpKernelInterface from Symfony, but largely only the
first (Request) argument. It promotes onion-style architectures. It's
widely used, and folks tend to talk about implementing StackPHP, not
the HttpKernelInterface, which is why I mention it separately here.

----

The above are examples of server-side middleware. You can use the same
patterns for client-side as well, but the only place I've really seen
that done in PHP is guzzle; it uses the same signature as
Connect/ExpressJS. I think we should be careful to specify *which*
environment we're specifically targeting with any such proposal, as
I'm not convinced middleware is a one-size-fits-all paradigm for both
environments.

Also, there are good use cases and rationales for *each* style of
middleware presented. As a result, I honestly do not think any
standard around middleware should dictate a *single* style. I'd rather
see enumeration of the different styles, so folks can say "implements
Middleware X".

It's relatively easy to wrap one style in another. As such, having an
enumeration of the types would facilitate libraries that can do that
sort of wrapping, allowing portability of middleware between projects
using different styles.

--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

Michael Dowling

unread,
Sep 10, 2015, 1:41:10 PM9/10/15
to php...@googlegroups.com
Just to clarify:

> You can use the same patterns for client-side as well, but the only place I've really seen that done in PHP is guzzle; it uses the same signature as
Connect/ExpressJS.

Guzzle uses a functional style with promises:

fn(RequestInterface $request, array $options): Promise<ResponseInterface, Error>

Using a fn(request) -> response style is the preferred method of middleware in Clojure (see Ring and HttpKit).

liuggio

unread,
Sep 11, 2015, 5:25:54 AM9/11/15
to php...@googlegroups.com
>> Honestly I also wonder why it has not yet been defined (I found nothing
>> searching on old threads).

sorry I just wanted to say that maybe I was missing something if you had not already proposed anything about this

> The concept is properly termed "middleware".

the reason why in the core-languages (node, golang etc) 
there's no any middleware term because is an implementation detail,
placing the "next" in the firm assumes that you have a pipe of middlewares,
and this is not a simple handling of the request/response
and that's why I've created 2 interfaces 

the scope of the RFC

and the middleware interface (still not in the scope of the RFC)

Also, there are good use cases and rationales for *each* style of
> middleware presented. 

I agree only if we decouple the term middleware"s" from the http handling

> As a result, I honestly do not think any
standard around middleware should dictate a *single* style. I'd rather
see enumeration of the different styles, so folks can say "implements Middleware X".

IMHO a big  -1

I firmly believe that a standard on HTTP will help the community,
the HTTP handling is something that other languages already have in the core,
and this RFC is not OT we shound't forget how the Symfony/HTTPKernelInterface really helped(still helping) the PHP ecosystem pushing forward the interoperability among libs.

If we close this RFC we will reduce the interoperability widening the gap between framework.

Thanks

giulio aka liuggio



 


Woody Gilk

unread,
Sep 11, 2015, 2:36:30 PM9/11/15
to php...@googlegroups.com
These interfaces are incorrect. There is only one signature, and it is:

public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next) : ResponseInterface

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

liuggio

unread,
Sep 11, 2015, 3:42:42 PM9/11/15
to php...@googlegroups.com
Thanks for you comment,

> These interfaces are incorrect. There is only one signature,

I hope your future comments will be polite and constructive.

The interface you wrote look like a middleware interface (I wrote my point of view above)
and it has also a "callable" that is not consistent and explicit, 
If I had to write a middleware interface with that style I'd replace the "callable" for  
the same interface name, I prefer to have a better explicit interface for 'next',
but
the idea of this RFC is to define the req/resp handler interface first and then maybe when we agree all we cal also define a middleware thing.

thanks

g.


--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/Ew36Ng5EwXE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
 __________________liuggio_________________________________
 
  __/|_      We reject kings, presidents and voting.
/o )   \/    We believe in rough consensus
)__ v _/\          and running code  (I.E.T.F. credo)
______________________________________________________________

Woody Gilk

unread,
Sep 11, 2015, 4:36:07 PM9/11/15
to php...@googlegroups.com
There is no separate interface for a middleware. Each of the middleware use the interface I provided. I am not trying to rude, but this is already well defined by http://relayphp.com/

Regards,

Matthew Weier O'Phinney

unread,
Sep 11, 2015, 6:55:49 PM9/11/15
to php...@googlegroups.com


On Sep 11, 2015 1:36 PM, "Woody Gilk" <woody...@gmail.com> wrote:
>
> These interfaces are incorrect.

Who made you the arbiter of correct and incorrect?

The interfaces I provided in my post all exist, are documented, and are widely used. None is more correct than any other; they offer different capabilities and arose out of different needs.

> There is only one signature, and it is:
>
> public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next) : ResponseInterface

This is the signature originally developed in Connect, and later adopted in Conduit (which became Stratigility), Relay, and Slim 3. It is not the *one* and *only* signature, as I pointed out previously. Stack and Lumen have other signatures, which are equally capable, and other signatures also exist.

> To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/CAGOJM6%2Bx4uCV5m9kG0FXyfUqU29bbJYJ%2BG0PWDGRMZAd9HrwkA%40mail.gmail.com.

Woody Gilk

unread,
Sep 11, 2015, 7:04:58 PM9/11/15
to php...@googlegroups.com
On Fri, Sep 11, 2015 at 5:55 PM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:
The interfaces I provided in my post all exist, are documented, and are widely used. None is more correct than any other; they offer different capabilities and arose out of different needs.
... 
Who made you the arbiter of correct and incorrect? 

Then let me be more clear...

These interfaces are incorrect because:

1. they use a reference for & $response, which is going to be wrong no matter what the interface is. A major point of immutability in PSR-7 is avoidance of side effects and forcing the usage of a reference is exactly the opposite of avoiding side effects.

2. Having an addNext method implies things that are not absolutely true:
    2.1. that the only viable middleware container is one that is not immutable
    2.2. that the exact order of the interfaces will be preserved, no matter what other methods exist
    2.3. extending from the middleware interface is a given

As per previous discussions, I think that Relay was the first (or one of) to definite an interface for PSR-7 middleware and we should consider it the canonical signature _for PSR-7_.

Woody Gilk

unread,
Sep 11, 2015, 7:09:47 PM9/11/15
to php...@googlegroups.com
Ah, and by "previous discussions" I mean the one that was just had on thephpleague [1] which I somehow thought happened on FIG. Apologies for conflating them.

Matthew Weier O'Phinney

unread,
Sep 11, 2015, 8:58:17 PM9/11/15
to php...@googlegroups.com


On Sep 11, 2015 6:04 PM, "Woody Gilk" <woody...@gmail.com> wrote:
>
> On Fri, Sep 11, 2015 at 5:55 PM, Matthew Weier O'Phinney <mweiero...@gmail.com> wrote:
>>
>> The interfaces I provided in my post all exist, are documented, and are widely used. None is more correct than any other; they offer different capabilities and arose out of different needs.
>>
>> ... 
>>
>> Who made you the arbiter of correct and incorrect? 
>
>
> Then let me be more clear...
>
> These interfaces are incorrect because:
>
> 1. they use a reference for & $response, which is going to be wrong no matter what the interface is.

I believe we may be talking about different things, then. Which interfaces are you referring to, exactly? In my original post on this thread, I referenced WSGI, Rack, Node, and Connect. What are you referring to?

> A major point of immutability in PSR-7 is avoidance of side effects and forcing the usage of a reference is exactly the opposite of avoiding side effects.

You don't need to lecture me on PSR-7; I was editor of the proposal.

> 2. Having an addNext method implies things that are not absolutely true:

This statement tells me you're talking about something I've not seen; can you link to where you're seeing this method? I clearly missed something along the way, and I'm not seeing it in this thread.

>     2.1. that the only viable middleware container is one that is not immutable
>     2.2. that the exact order of the interfaces will be preserved, no matter what other methods exist
>     2.3. extending from the middleware interface is a given
>
> As per previous discussions, I think that Relay was the first

Relay followed the lead of Stratigility (née Conduit), which is a port of Connect. I bring this up to ensure the history is clear; i.e., it's an established pattern used elsewhere, and tested in production applications in other languages.

> (or one of) to definite an interface for PSR-7 middleware and we should consider it the canonical signature _for PSR-7_.

Why?

Granted, I've clearly implemented the same signature in projects I've authored. However, the fact is that other patterns are equally established and production-tested (Stack is used all over the place; Lumen is gaining traction; etc.). What makes *this* *one* more viable than others? Just asserting it doesn't make it so.

Also, the fact that it might be the first used by dedicated psr-7 libraries doesn't make it better in and of itself. You can easily use psr-7 instances in any of the other established patterns just as well.

My point is: make clear arguments detailing why the pattern is the *single* one that should be proposed. While I personally prefer this pattern, I can see clear merits in the others as well. I think strong cases will be necessary if you want to persuade users of other patterns.

I also think it's acceptable to acknowledge all of the patterns in such a specification, and would argue that doing so is more likely to achieve consensus. Standards (outside of FIG) have done similarly where warranted.

Arguing that a single one is the only "correct" approach is polarizing, if you cannot make a strong case based on technical merits.

>
> --
> Woody Gilk
> http://about.me/shadowhand
>

> --
> You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
> To post to this group, send email to php...@googlegroups.com.

> To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/CAGOJM6Jb%3DO3j%2BuNtuROLqoNrGFC6zAyrK1Gf8up%3D5_Ps_TM_VQ%40mail.gmail.com.

liuggio

unread,
Sep 11, 2015, 9:23:44 PM9/11/15
to php...@googlegroups.com
Thanks for comments 

1. they use a reference for & $response, which is going to be wrong no matter what the interface is. A major point of immutability in PSR-7 is avoidance of side effects and forcing the usage of a reference is exactly the opposite of avoiding side effects.

I added the & in a second commit after a discussion about that,
the concept was to simplify the use-case as GoLang does not relying on the return,
but the cons are pretty strong is something to discuss because there's pro/cons that's the reason of the prefix "RFC"

2. Having an addNext method implies things that are not absolutely true:

    2.3. extending from the middleware interface is a given

I totally agree with you about 2.1 and 2.2 but not for the last one having an interface instead of callable will reduce the compatibility no more function/closure/dogs/ball 
but it will enforce the signature of the standard, having the interface in the type hinting is a huge pro also because explain how to call the next in the readme is a smell of bad OOD,
the callable is good for functional approach that is good also in PHP but not for a strict standars (in some language there's a converter from functional approach to the object one).

But:
> the idea of this RFC is to define the req/resp handler interface first and then maybe when we 
> agree all we cal also define a middleware thing.

Middleware "!==" handler

Mapping a response to a given request is one job
Pass the req/resp to another/next/prev/with an event dispatcher/on the sky is another job 

Don't you think are different things?

@Matthew Weier O'Phinney
>This statement tells me you're talking about something I've not seen; can you link to where 
>you're seeing this method? 

Don't take this as an implementation I commit it only to face the fact that the middleware is another thing... 




As per previous discussions, I think that Relay was the first (or one of) to definite an interface for PSR-7 middleware and we should consider it the canonical signature _for PSR-7_.

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/Ew36Ng5EwXE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Woody Gilk

unread,
Sep 11, 2015, 9:55:47 PM9/11/15
to php...@googlegroups.com
On Fri, Sep 11, 2015 at 7:58 PM, Matthew Weier O'Phinney
<mweiero...@gmail.com> wrote:
>
> > 1. they use a reference for & $response, which is going to be wrong no matter what the interface is.
>
> I believe we may be talking about different things, then. Which interfaces are you referring to, exactly?

https://github.com/liuggio/http/blob/master/HttpHandlerInterface.php
as in the thread that I was replying to.

>> (or one of) to definite an interface for PSR-7 middleware and we should consider it the canonical signature _for PSR-7_.
>
> Why?
>
> Granted, I've clearly implemented the same signature in projects I've authored. However, the fact is that other patterns are equally established and production-tested (Stack is used all over the place; Lumen is gaining traction; etc.).

The most obvious reason is that it works extremely well and is a
clearly established pattern. It works better than other signatures
because:

1. it doesn't require references
2. it works well with immutable objects since nothing has implicit
state, eg the $next callable will passed exactly what the current
middleware decides
3. it allows the user to define what implementation of PSR-7 should be
used, rather than forcing the middleware to dictate it (or use a
factory to avoid doing so)

As for Stack, it was conceived before PSR-7 existed and is not
actually framework agnostic, since the interfaces for HttpFoundation
were (more or less) bundled with HttpKernel.

As for Lumen, it suffers exactly the same problem as HttpKernel... it
is conceived with the theory that Lumen is the default choice.

Both Stack and Lumen make it inherently harder to achieve complete
dependency inversion.

Hopefully that provides further clarity to my reasoning.

Regards,

Woody Gilk

unread,
Sep 11, 2015, 9:59:54 PM9/11/15
to php...@googlegroups.com
On Fri, Sep 11, 2015 at 8:23 PM, liuggio <liu...@gmail.com> wrote:
> Mapping a response to a given request is one job
> Pass the req/resp to another/next/prev/with an event dispatcher/on the sky
> is another job
>
> Don't you think are different things?


I do not. As seen in Relay, all the middleware objects can be used as
HTTP handlers. The middleware "manager" is just a collector that keeps
a queue of middleware and executes them in order and returns the last
response. The only difference is that the manager has no $next, so
it's signature only takes $request and $response. (Perhaps with
$response being optional.)
Reply all
Reply to author
Forward
0 new messages