Warning! This post was published over 8 years ago, so it can contain outdated information. Bear this in mind when putting it into practice or leaving new comments.
I was digging into Zend Expressive and how to use controllers that allow me to share dependencies between different routes, instead of having to use different middlewares every time.
Abdul wrote a great article on this subject that you can find here, which also became part of Expressive’s cookbook some time later.
This is a perfect approach that easily allows to reuse some code, but then I thought how to do something similar in a rest environment, having a single class with different dispatchable methods that will be called depending on the request’s HTTP method.
We need some default behavior and some code that can be reused, so this could be our AbstractRestController.
It creates an invokable class that dispatches different methods based on the request HTTP method, passing the $request, $response and next middleware to all of them.
By default, it makes all the methods return a 405 status, so that we can leave them unimplemented in concrete controllers and any consumer knows that they are not allowed.
This class will be the base for any rest controller.
Concrete implementations
Once we have the abstract controller, we can define any class extending it.
This class overrides only 4 of the public methods, returning custom responses.
We will usually inject some service on this controller and use it to perform CRUD operations. In this example I have just hardcoded the responses.
Register the route
Once the controller is created, we need to register a route setting this controller as the middleware and allowing any method, since the HTTP method check will be performed in the controller itself.
If you have created your app starting from the skeleton application, you just need to open the config/autoload/routes.global.php file and add the route and register your controller as a service.
The registration of the controller will depend on the container implementation and how it needs to be created. In this case I’m using the Zned\ServiceManager component, and the controller is a simple invokable service without dependencies.
Also, the route definition could slightly change depending on the chosen router. I’m using FastRoute.
When the allowed_methods key is not set, it allows any method by default.
Now, a GET request to the /rest/user route will return the list of users, a DELETE request to /rest/user/123 will delete the user 123 and so one.