Router
A tiny, attribute-driven HTTP router that turns any PHP class into a fully documented REST controller. It powers request dispatching, the route:list CLI, and your OpenAPI generator.
1. Installation
composer require monkeyscloud/monkeyslegion-routerThe package only brings psr/http-message and the MonkeysLegion HTTP kernel.
2. Defining Routes with #[Route]
Annotate public methods in any controller class:
namespace App\Http\Controller;
use MonkeysLegion\Router\Attributes\Route;
use Psr\Http\Message\ResponseInterface;
final class PostController
{
#[Route('GET', '/posts', summary: 'List posts', tags: ['Post'])]
public function index(): ResponseInterface { /* … */ }
#[Route(['GET','POST'], '/posts', name: 'post_create')]
public function create(): ResponseInterface { /* … */ }
#[Route('DELETE', '/posts/{id:[0-9]+}', summary: 'Delete one')]
public function delete(int $id): ResponseInterface { /* … */ }
}Parameter | Type | Purpose |
|---|---|---|
methods | string|string[] | HTTP verb(s) to match |
path | string | URI template ({id} automatically typed as string, or supply a regex) |
name | string | Optional route name / OpenAPI operationId |
summary | string | One-liner for Swagger UI |
tags | string[] | Grouping labels in docs |
3. Registering Controllers
use DI\Container;
use MonkeysLegion\Router\Router;
use MonkeysLegion\Router\RouteCollection;
// services.php
return [
RouteCollection::class => fn() => new RouteCollection(),
Router::class => fn($c) => new Router(
$c->get(RouteCollection::class),
$c // any PSR-11 container
),
];Then, at boot:
$router = $container->get(Router::class);
$router->registerController(App\Http\Controller\PostController::class);
// or entire folders via Core’s RouteLoader4. Imperative & Dynamic Routes
Need a route outside a controller class? Call add():
$router->add(
methods: ['GET'],
path: '/healthz',
handler: [HealthController::class, 'probe'],
name: 'health_check',
tags: ['Ops'],
);Both attribute- and imperative routes live in the same RouteCollection.
5. Dispatching with PSR-15
use Laminas\Diactoros\ServerRequestFactory;
use Middlewares\Utils\Dispatcher;
$request = ServerRequestFactory::fromGlobals();
$response = Dispatcher::run(
[
// global middleware (auth, body-parser, etc.)
$router->getMiddleware(), // performs route matching & invokes handler
],
$request
);
(new Laminas\HttpHandlerRunner\Emitter\SapiEmitter())->emit($response);6. CLI Goodies
php vendor/bin/ml route:list
# ───────────────────────────────────────────────────────────────
# METHOD PATH NAME
# ───────────────────────────────────────────────────────────────
# GET /posts post_index
# POST /posts post_create
# DELETE /posts/{id} post_delete
# ───────────────────────────────────────────────────────────────
php vendor/bin/ml openapi:export > openapi.yaml # full spec7. Under the Hood
Class | Role |
|---|---|
MonkeysLegion\Router\Attributes\Route | PHP 8 attribute storing route metadata |
MonkeysLegion\Router\Route | Immutable value object (methods, path, handler, docs) |
MonkeysLegion\Router\RouteCollection | Iterable registry of Route objects |
MonkeysLegion\Router\Router | Scans controllers, validates paths, adds routes programmatically |
8. Extending the Router
Path parameter metadata—add descriptions, examples, or custom validators.
API versioning—prepend a version prefix in Router or at the attribute level.
Per-route middleware—store middleware stacks on the Route object and apply during dispatch.
Pull requests are welcome—check the GitHub issues for “good first issues”.
License
MIT © 2025 MonkeysCloud