Package proposal: PSR-7 middlewares

486 views
Skip to first unread message

hannesvdvreken

unread,
Sep 10, 2015, 4:38:57 AM9/10/15
to thephpleague
Hi all!

I'd like to propose a package that I recently created because I felt it was missing: middlewares for PSR-7.


StackPHP is the alternative for Symfony HTTP Foundation objects. Guzzle v6 middlewares were an inspiration for this package as well, except that this package doesn't need promises.

It's a package with some interfaces for middlewares that pass on PSR-7 request objects to the core of a layered structure of middlewares, potentially altering the Request object. Potentially the middlewares send a Response object without presenting the Response object to the next layer, in case of a firewall, or a matched route, or matched IP address. The core of the layered structure will not be knowledgeable of a next layer, that's why it extends the `Core` interface.

See this image (http://stackphp.com/img/onion.png) on how it works. Basically the Core implements the `Core` interface, the layers on top implement the `Kernel` interface, which is an extension of `Core`. Every Kernel is made aware of the next layer (wether that's a Core, or a Kernel (which is also a Core), it doesn't care) via the `setNextCore` method which is implemented with the NextCore trait.

Every object can be constructor injected with whatever. There is no limitation on the constructor as is the case with KernelInterface objects used with StackPHP.

Currently it has no implementing packages, except for the experimental hannesvdvreken/route-middleware, which takes a RouteCollection from the league/route package. If this package is accepted before league/route v2 is tagged, the RouteCollection can maybe even implement the Core interface? If not the route-middleware can exist on its own.


I also see a PSR-7 middleware -> StackPHP conversion package possible using the Symfony PSR-7 Bridge package (symfony/psr-http-message-bridge).

Compared packages:

untested, unreleased, based on callables, doesn't make a difference between a core and a kernel, but it is created by Beau (also behind StackPHP)

too many dependencies: not stable

Cheers!

Sági-Kazár Márk

unread,
Sep 10, 2015, 4:53:45 AM9/10/15
to hannesvdvreken, thephpleague
Hi!

There is also an implementation created by Paul M. Jones: http://relayphp.com/

This also looks good.

Regards,
Mark

--
You received this message because you are subscribed to the Google Groups "thephpleague" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague...@googlegroups.com.
To post to this group, send email to thephp...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/thephpleague/d2fcff50-1fef-466d-aa4f-12946ece322f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

hannesvdvreken

unread,
Sep 10, 2015, 9:41:48 AM9/10/15
to thephpleague, vandevrek...@gmail.com
Hmm, didn't pick up that RelayPHP implementation before.

I told some people I wanted to create something like this, and no-one mentioned RelayPHP existed.
Also searched on Packagist.org but didn't see that pop up.

Probably I asked the wrong people and used the wrong keywords.

Anyway, that Relay thing looks complicated.
Why pass on an empty Response object when there really only is a Request to start with.
It also makes use of a callable definition. No middleware must implement the interface, though it can.
With PHP 7 return types coming up, that doesn't seem future proof.
In the other direction: creating a wrapper object for callable middlewares that implement an interface IS an option.

I think the use of separate interfaces in my package (Cores and Kernels) ticks the box for the Interface Segregation Principle.
My implementation is simple and extendible, so why ask more? Even the Stack Builder could be dropped.

(Probably going to make the Stack object a Kernel as well so I can append the next core to the last Kernel)

What do you think? You can give it a spin, look around, tell me what documentation is missing, ...

Cheers,
Hannes Van De Vreken

Woody Gilk

unread,
Sep 10, 2015, 9:43:11 AM9/10/15
to Sági-Kazár Márk, hannesvdvreken, thephpleague
I disagree that this is a viable solution, because it only accepts a RequestInterface [1] and not a Request _and_ Response like Relay and other PSR-7 middleware systems that already exist. In my opinion, Relay is much better defined for PSR-7 and has a lot of thought behind it.

Woody Gilk

unread,
Sep 10, 2015, 9:44:51 AM9/10/15
to hannesvdvreken, thephpleague

On Thu, Sep 10, 2015 at 8:41 AM, hannesvdvreken <vandevrek...@gmail.com> wrote:
Why pass on an empty Response object when there really only is a Request to start with.

Because doing so means that no middleware needs to know which concrete implementation of PSR-7 is being used. It simply takes the incoming response and transforms it however it needs to, and then passes it along.

It is MUCH better than forcing a middleware to create a response itself.

Regards,

Woody Gilk

unread,
Sep 10, 2015, 9:46:23 AM9/10/15
to hannesvdvreken, thephpleague
On Thu, Sep 10, 2015 at 8:41 AM, hannesvdvreken <vandevrek...@gmail.com> wrote:
It also makes use of a callable definition. No middleware must implement the interface, though it can.

Any middleware could implement an interface, but it doesn't need to. Callable is a perfectly acceptable type hint and works with closures, classes, and functions. It is the most flexible option and works equally well for any situation.

hannesvdvreken

unread,
Sep 10, 2015, 9:50:31 AM9/10/15
to thephpleague, mark.sa...@gmail.com, vandevrek...@gmail.com
Hi,

Agreed that creating a Response object requires you to choose an implementation, like Guzzle PSR-7 or Zend Diactoros.
But in the idea of a Request->Response middleware it's not really common to pass on a Response object
while going "inward" into the stack

See:

Woody Gilk

unread,
Sep 10, 2015, 9:54:25 AM9/10/15
to hannesvdvreken, thephpleague, mark.sa...@gmail.com

On Thu, Sep 10, 2015 at 8:50 AM, hannesvdvreken <vandevrek...@gmail.com> wrote:
But in the idea of a Request->Response middleware it's not really common to pass on a Response object

Symfony only has a single implementation of HttpKernel, so it is an apples or oranges comparison. Guzzle uses Promises, and does actually typehint against a ResponseInterface instead of directly creating a response[1]. Just because it hasn't been done before doesn't make it wrong. As I said, a lot of thought went into Relay (I helped test it) and the current interfaces work REALLY well.

hannesvdvreken

unread,
Sep 10, 2015, 10:06:27 AM9/10/15
to thephpleague, vandevrek...@gmail.com, mark.sa...@gmail.com
Hi,

> Symfony only has a single implementation of HttpKernel

I'm trying to understand why you say HttpKernelInterface has only one implementation, as it is the base for every StackPHP middleware, like the PHP league's Robot middleware (https://github.com/thephpleague/stack-robots/blob/master/src/Robots.php#L9) and many others. What did you mean?

> Just because it hasn't been done before doesn't make it wrong.
Didn't say that. It's a change for people coming over from Symfony Request object based middlewares (StackPHP), that's all.

> the current interfaces work REALLY well.
I tried it, the interface does work, no doubt about that. Did you try mine?
It's a pity I didn't know about it before yesterday. If the adoption was higher,
I would have known about it and didn't even start thinking about a clone.

Woody Gilk

unread,
Sep 10, 2015, 10:19:45 AM9/10/15
to hannesvdvreken, thephpleague, Márk Sági-Kazár

On Thu, Sep 10, 2015 at 9:06 AM, hannesvdvreken <vandevrek...@gmail.com> wrote:
I'm trying to understand why you say HttpKernelInterface has only one implementation, as it is the base for every StackPHP middleware, like the PHP league's Robot middleware (https://github.com/thephpleague/stack-robots/blob/master/src/Robots.php#L9) and many others. What did you mean?

I mean that all of the middlewares use Symfony HttpFoundation, so there is (effectively) only one implementation on ResponseInterface, despite what the type hints say.

hannesvdvreken

unread,
Sep 10, 2015, 10:35:40 AM9/10/15
to thephpleague, vandevrek...@gmail.com, mark.sa...@gmail.com
Hi,

Oh yeah, I see :-). You said: Symfony only has a single implementation of HttpKernel. But "HttpKernel" was supposed to be "Response object". No problem.

Not really apples and oranges imho, just type hinted with interfaces, so more decoupled. Does it matter wether middlewares return a Response object implemented by Guzzle, or Zend, or whatever? The returned Response object can be of a different implementation than the one passed to a RelayPHP compatible middleware's __invoke method. Zend's Emitter for example outputs any type of ResponseInterface object with header() and output buffer calls.

Sági-Kazár Márk

unread,
Sep 10, 2015, 11:15:45 AM9/10/15
to hannesvdvreken, thephpleague
Well, I haven't looked at Relay or your implementation too carefully.

I agree that in case of a middleware implementation a simple interface is better than simple callables. The main reason is typehinting of arguments: you cannot check it in case of a callable (actually you can with reflection, but that's insane), you can in case of an interface.


Woody wrote:

> Because doing so means that no middleware needs to know which concrete implementation of PSR-7 is being used. It simply takes the incoming response and transforms it however it needs to, and then passes it along.

It depends. If your middleware stack wraps a central middleware which handles your request, then the response needs to be created at some point. This implies the middleware is used together with application logic. I think that things work in StackPHP just like the same.

To workaround the requirement of knowledge, we use discovery and factories at PHP HTTP:

https://github.com/php-http/discovery
https://github.com/php-http/message-factory

For the record: Noone says Relay is wrong.

Hannes: I think this package would be a good fit for PHP HTTP, I was also thinking about something like this, but I found relay and didn't have the time.

Regards,
Mark

Sági-Kazár Márk

unread,
Sep 10, 2015, 11:21:12 AM9/10/15
to hannesvdvreken, thephpleague
One thing that I found weird: the NextCore thing. I think it should be a stateless thing.

I like how Ross Tuck solved this question in Tactician:

https://github.com/php-http/message-factory
https://github.com/thephpleague/tactician/blob/master/src/Middleware.php

While this again adds some callable to the stuff, it is only used internally. You can also cache the middleware stack this way without the need for setting the next core each time.

And a naming thing: doesn't 'Handler' sound better than 'Core'?

At least Core seems to be a joker naming to me: you don't know what it does, but it fits.

Colin O'Dell

unread,
Sep 10, 2015, 11:42:15 AM9/10/15
to Sági-Kazár Márk, hannesvdvreken, thephpleague
But in the idea of a Request->Response middleware it's not really common to pass on a Response object
> while going "inward" into the stack

There are two or three common patterns, and this is one of them.  I read a great blog post a few months ago listing and comparing the different patterns, but I can't seem to find it anymore.  If I come across it again I'll pass it along :)

--
You received this message because you are subscribed to the Google Groups "thephpleague" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague...@googlegroups.com.
To post to this group, send email to thephp...@googlegroups.com.

hannesvdvreken

unread,
Sep 10, 2015, 1:48:21 PM9/10/15
to thephpleague

Woody Gilk

unread,
Sep 10, 2015, 2:07:32 PM9/10/15
to hannesvdvreken, thephpleague
Hannes,

FWIW, I think this conversation was really valuable and I hope you aren't too demoralized by the result. :) A good learning experience for everyone.

Regards,

--
You received this message because you are subscribed to the Google Groups "thephpleague" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague...@googlegroups.com.
To post to this group, send email to thephp...@googlegroups.com.

Woody Gilk

unread,
May 10, 2016, 9:17:18 AM5/10/16
to thephpleague, vandevrek...@gmail.com
I've proposed a MiddlewareInterface to FIG https://github.com/php-fig/fig-standards/pull/755
To unsubscribe from this group and stop receiving emails from it, send an email to thephpleague+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages