A lightweight regular expression based request router with support for dependency injection

0.1.0 2018-12-29 21:45 UTC


A lightweight regular expression based request router with support for dependency injection targeted at projects consuming the recommendations of the PHP-FIG.

Main Features


Installation is made with composer

composer require apinephp/dist-route

The package requires PHP 7.2 or newer.

Usage Example

require '/path/to/vendor/autoload.php';

use Apine\DistRoute\Router;

$router = new Router($container);
$router->map(['GET'], '/users', UserController::class . '@all');
$router->get('/user/{id:(\d+)}', UserController::class . '@one');

$response = $router->handle($serverRequest);

Define a route

Routes are defined by calling the mapping methods of the router like map() :

$router->map($methods, $pattern, $handler);

The $methods is a list of one or many uppercase HTTP methods for which a route should match.

The $pattern defines a placeholder for matching using the syntax {name} which creates a placeholder named name. It is possible to change the regex pattern which a placeholder matches by writing the regex after the name and a colon. It is also possible to mark a placeholder as optional by adding a question mark (?) before its name.

$router->map(['GET'], '/user/{id}', 'handler');
$router->map(['GET'], '/user/{id:(\d+)}', 'handler');
$router->map(['GET'], '/user/{?id}', 'handler');

The $handler parameter is the handler that should be executed if the route matches a ServerRequest. It may be an instance of MiddlewareInterface, a Closure, the name of a function, or the fully qualified name of a class and the name of a method separated by a @. The handler must return a ResponseInterface.

Shorthand methods

The router has shorthand methods for the following request methods : GET, POST, DELETE, PUT, OPTIONS, HEAD, and TRACE.

Prefixed Routes (Subrouting)

The group() method allows to define multiple routes under a common prefix pattern. The $pattern parameter is a pattern as define above that will be prefixed to the child routes. The $closure parameter is a function called within the context of the router. It must receive as its only parameter an instance of RouterInterface which represents the current router.

The following will have the same effect as the example above:

$router->group('/user', function (RouterInterface $mapper) {
 $mapper->map(['GET'], '/{id}', 'handler');
 $mapper->map(['GET'], '/{id:(\d+)}', 'handler');
 $mapper->map(['GET'], '/{?id}', 'handler');

Using middlewares

A middleware is added to the router using the use() method. The middleware should be an instance of MiddlewareInterface as defined in the PSR-15 HTTP Handlers recommendation from the PHP-FIG. The middleware will be applied to all the requests being treated regardless a matching route is found or not.


Dispatching (handling) a request

A request is handled by calling the handle() method of the router. The method accepts an instance of ServerRequestInterface.

The method throws an RouteNotFoundException if none of the routes matched the request. Otherwise, it returns the instance of ResponseInterface from the handler.

Execution priority

Routes and middlewares are seeked through in the order at which they were registered in the router. It works like a queue.

Let's say you registered a route then a middleware in the following fashion:

$router->get('/test/{number:([0-9]+)}', 'routeFunction');

It this example, the router will first try to match the route to the request it receives. If it matches, the router will execute the callable of the route then return its result. Otherwise, it will execute to the middleware.

Hence it is a great idea to define the middlewares first then define routes.