il4mb/routing

Deterministic routing engine with an HTTP attribute router adapter (priority, fallback, wildcard matching, tracing, and reloadable rules)

Maintainers

Details

github.com/il4mb/Routing

Source

Issues

Installs: 62

Dependents: 1

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

pkg:composer/il4mb/routing

v0.2.0-alpha 2026-01-06 18:49 UTC

This package is auto-updated.

Last update: 2026-01-06 18:51:38 UTC


README

This repository provides a deterministic routing engine that can be embedded into infrastructure-style software:

  • HTTP applications (controller routing)
  • API gateways and reverse proxies (upstream selection)
  • Programmable network services (policy routing)
  • Mail servers (message classification and delivery policy)

The project contains both:

  • a protocol-agnostic core (src/Engine/*) with explicit match and decision phases, and
  • a legacy HTTP router (src/Router.php) that compiles attribute routes into the core engine.

The intent is to keep routing decisions explainable, testable, and observable.

Requirements

  • PHP 8.1+
  • Composer (for autoloading)

Installation

composer require il4mb/routing

Quick Start (HTTP Attribute Routes)

use Il4mb\Routing\Http\Method;
use Il4mb\Routing\Http\Request;
use Il4mb\Routing\Map\Route;
use Il4mb\Routing\Router;

final class AdminController
{
    #[Route(Method::GET, '/admin/home', priority: 50)]
    public function home()
    {
        return 'ok';
    }

    // Fallback route (only used if nothing else matches)
    #[Route(Method::GET, '/{path.*}', fallback: true)]
    public function notFound(string $path, Request $req, Response $res, callable $next)
    {
        return ['error' => 'not_found', 'path' => $path];
    }
}

$router = new Router(options: [
    // Production deployments typically disable this side-effect.
    'manageHtaccess' => false,

    // chain|first|error_on_ambiguous
    'decisionPolicy' => 'first',

    // Enable only while debugging.
    'debugTrace' => true,
]);

$router->addRoute(new AdminController());

$response = $router->dispatch(new Request());
echo $response->send();

When debugTrace=true, the router stores trace data into:

  • Request::get('__route_trace')
  • Request::get('__route_decision')

Using the Core Engine (Protocol-Agnostic)

The engine routes a RoutingContext through a deterministic pipeline.

use Il4mb\Routing\Engine\DecisionPolicy;
use Il4mb\Routing\Engine\RouteDefinition;
use Il4mb\Routing\Engine\RouteTable;
use Il4mb\Routing\Engine\RouterEngine;
use Il4mb\Routing\Engine\RoutingContext;
use Il4mb\Routing\Engine\Matchers\HostMatcher;
use Il4mb\Routing\Engine\Matchers\PathPatternMatcher;
use Il4mb\Routing\Engine\Matchers\ProtocolMatcher;

$routes = [
    new RouteDefinition(
        id: 'proxy.payments.eu',
        target: ['cluster' => 'payments-eu'],
        matchers: [
            new ProtocolMatcher('https'),
            new HostMatcher('payments.example.com'),
            new PathPatternMatcher('/v1/**'),
        ],
        priority: 100,
    ),
];

$engine = new RouterEngine(new RouteTable($routes), policy: DecisionPolicy::FIRST);

$ctx = new RoutingContext(protocol: 'https', host: 'payments.example.com', path: '/v1/charge', method: 'GET');
$outcome = $engine->route($ctx);

if ($outcome->ok) {
    $selected = $outcome->decision->selected[0] ?? null;
    // $selected->target contains your adapter payload
}

Documentation

Release notes

Examples

Tests

Run the lightweight (dependency-free) tests:

php -d zend.assertions=1 -d assert.exception=1 tests/run.php

Design Philosophy

  • Explicit over implicit: matching, ordering, and decision policy are visible.
  • Configuration as code: routes can be loaded as typed objects and tested.
  • Predictable execution: deterministic tie-breaking (priority → specificity → id).
  • Minimal magic: adapters own side-effects; the core engine stays pure.

License

MIT. See LICENSE.