icom/ framework

One route. No guessing.

Match a method and path, resolve explicit arguments, return a PSR-7 response.

Define routes

example
use Icom\Http\Response;
use Psr\Http\Message\ServerRequestInterface as Request;

$app->get('/hello/{name}',
    fn (Request $request, string $name) =>
        Response::json(['hello' => $name])
)->name('hello');

$app->post('/notes', [NoteController::class, 'store']);
$app->put('/notes/{id}', [NoteController::class, 'replace']);
$app->patch('/notes/{id}', [NoteController::class, 'update']);
$app->delete('/notes/{id}', [NoteController::class, 'destroy']);

Generate URLs

example
$url = $app->router->url('hello', ['name' => 'ສະບາຍດີ']);
// Values are percent-encoded, never concatenated into route patterns.

Predictable matching

Static routes take precedence for the same method. Dynamic routes match in registration order. Parameters match one path segment and are decoded once. Routes are case-sensitive, with exact trailing-slash matching. GET supports HEAD with an empty body. Explicit HEAD and OPTIONS routes override automatic behavior. Unknown paths return 404; other methods return 405 with Allow. Automatic OPTIONS returns 204. Avoid slash characters inside route parameters: web servers differ in handling encoded slashes.

Controllers and contracts

Controllers may be closures, invokable class names or [Controller::class, method] arrays. Class-typed arguments use dependency injection. Named string and integer arguments come from route parameters; invalid integer input returns 400. Controllers must return ResponseInterface. Registration belongs at bootstrap, before the first request.

Inspect the route table

example
php bin/icom routes

Developer preview — benchmark claims require reproducible evidence.

Explore the architecture