zendframework / zend-expressive

PSR-15 middleware in minutes!
BSD 3-Clause "New" or "Revised" License
710 stars 197 forks source link

[Question] Are there any plans to make router an optional dependency for Zend\Expressive\Application ? #495

Closed Articus closed 7 years ago

Articus commented 7 years ago

The reason I am asking is pretty simple - all my Zend Expressive projects do not use \Zend\Expressive\Middleware\RouteMiddleware and \Zend\Expressive\Middleware\DispatchMiddleware. Zend\Expressive\Application::pipe and homebrewed middleware for API development were more than enough.

Direct usage of Zend Strategility is not a good option because it does not have container integration out of box and I ended up with a fake router that I have to add to container just to make Expressive happy.

So are there any conceptual concerns that require router to be mandatory dependecy? If no I can make PR to make it optional.

geerteltink commented 7 years ago

If you only need literal GET paths (/api/user) in your application then you can do without a router. If you need a regex path or support for POST,UPDATE,etc then you should use a router. That's what it's for. I can remember someone else asked this some time ago but I can't remember the long answer. But I remember it had no in it.

I think a router is essential and your use case sounds more like an edge case. At least that's from my own experience. Some of the basic sites I've build had at least a contact form, which needs the router to handle POST requests. Without the router you also can't use the UrlHelper and ServerHelper and some template plugins. I guess you can get away with a nullable router in your case.

Routing vs Piping Expressive provides two mechanisms for adding middleware to your application:

  • piping, which is a foundation feature of the underlying zend-stratigility implementation.
  • routing, which is an additional feature provided by zend-expressive.

That is taken from the Expressive docs. So basically if you take the routing away, all you have left is Stratigility. Add a container to Stratigility, copy the config loading from the skeleton and you have what you need.

Articus commented 7 years ago

Thank you for response and sorry for being a bit obscure. I did not mean that routing is not needed. I meant that in my case there is custom implementation of routing and dispatching inside custom middleware and that default implementation from Expressive is not needed.

Fully agree that this is an edge case. Personally I just wanted to reduce repetitive tasks for handling API calls as much as possible. But so far Expressive is flexible enough to support this scenario because Zend\Expressive\Middleware\RouteMiddleware and Zend\Expressive\Middleware\DispatchMiddleware are not added to pipeline automatically (and hopefully it stays that way :) ). And if I am not mistaken router inside Zend\Expressive\Application is needed only to construct these two middlewares.

weierophinney commented 7 years ago

Expressive exists to provide the common features required of the majority of middleware frameworks: dependency injection container integration, templating (if desired), error handling, and routing. Routing is explicitly one of the pieces Expressive addresses that Stratigility does not.

if I am not mistaken router inside Zend\Expressive\Application is needed only to construct these two middlewares

This is not entirely true: each of the various route(), get(), post(), etc. methods reference Zend\Expressive\Router\Route, and inject such instances into the composed router. Making the router optional would thus require additional checks in such methods for the existence of a router, and need to raise an exception if none is found. In other words, the bulk of the Application API would be useless if a router is not available.

The main point I wanted to make, though, is that providing routing was an explicit goal of Expressive; making it optional is not something we want to support.

If you do not pipe the route and/or dispatch middleware, and do not use the routing methods of Application, you can provide a dummy router. This is actually really easy with PHP 7, as you can use an anonymous class:

$app = new Application(
    new class implements RouterInterface {
        public function addRoute(Route $route) { }
        public function match(Request $request) {
            throw new Exception('Not implemented');
        }
        public function generateUri($name, array $substitutions = [], array $options = []) {
            throw new Exception('Not implemented');
        }
    },
    $container,
    $delegate,
    $emitter
);