Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Router Laravel Package

rareloop/router

Rareloop Router is a lightweight, fast PHP router built around PSR-7 and PSR-15. It supports route parameters, groups, middleware, named routes and route caching, making it easy to add clean, expressive routing to any PHP application without a full framework.

Deep Wiki
Context7

Getting Started

rareloop/router is a FastRoute-backed, Laravel-flavoured router that speaks PSR-7 in and PSR-7 out. It is a routing library, not a framework: it gives you route registration, groups, middleware, named routes and URL generation, and expects you to bring your own PSR-7 implementation, PSR-17 response factory and (optionally) PSR-11 container.

composer require rareloop/router \
    nyholm/psr7 nyholm/psr7-server   # or laminas-diactoros

Minimal bootstrap:

use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7Server\ServerRequestCreator;
use Rareloop\Router\Router;

$factory = new Psr17Factory();          // PSR-17 response factory
$router  = new Router($factory);        // optionally: new Router($factory, $container)

$router->get('/', fn () => 'Hello world');
$router->get('/posts/{id}', 'PostController@show');

$request  = (new ServerRequestCreator($factory, $factory, $factory, $factory))
    ->fromGlobals();
$response = $router->handle($request);

// emit $response with whatever emitter you already use (laminas-httphandlerrunner, etc.)

Where to look first:

  1. The README on GitHub — it is the primary documentation and the API surface is small enough to read in one sitting.
  2. src/Router.php — registration (get/post/put/patch/delete/options/any), group(), url(), handle().
  3. src/Route.php and src/RouteGroup.php — everything returned by a registration call is fluent, which is where middleware/names live.
  4. src/RouteParams.php and the callable resolver — this is how handler arguments get injected.

First real use case: you have an existing PSR-15 stack (Relay, Laminas Mezzio, a hand-rolled front controller) or a small JSON API, and you want Laravel-style route ergonomics without pulling in a framework. Drop the router at the end of your middleware pipeline and start registering routes.

Implementation Patterns

Handlers are closures, Controller@method strings, [Class::class, 'method'] arrays, or invokables. When a PSR-11 container is passed to the constructor, controller strings are resolved through it, so constructor injection works normally:

$router = new Router($factory, $container);
$router->get('/posts/{id}', 'PostController@show');

Route parameters arrive as handler arguments and via RouteParams. Name your method parameters after the placeholders, or type-hint RouteParams to read them explicitly:

$router->get('/posts/{id:\d+}', function (RouteParams $params) {
    return $params->get('id');
});

class PostController {
    public function show(RouteParams $params, PostRepository $posts) { /* ... */ }
}

Inline regex constraints ({id:\d+}) and FastRoute optional segments (/posts[/{page}]) both work — use them instead of validating in the handler.

Middleware is PSR-15, attached per route or per group, and resolved from the container when given a class string. Order matters: group middleware wraps route middleware, and both run before your handler.

$router->get('/admin', 'AdminController@index')
    ->middleware(AuthMiddleware::class)
    ->middleware(AdminOnlyMiddleware::class);

Groups handle prefixes, shared middleware and name prefixes — this is the pattern you will use most day-to-day:

$router->group('/api/v1', function (Router $router) {
    $router->get('/users', 'UserController@index')->name('users.index');
    $router->post('/users', 'UserController@store');
})->middleware(ApiAuth::class)
  ->name('api.');

Named routes + URL generation keeps redirects and links from hardcoding paths:

$router->get('/posts/{id}', 'PostController@show')->name('posts.show');

$url = $router->url('posts.show', ['id' => 42]);  // -> /posts/42

For a Laravel developer this is the route() helper equivalent; wrap it in a small helper or inject the router into your view layer.

Return values are flexible. Return a ResponseInterface for full control, or a string/array-ish scalar and let the configured response factory build the response. For JSON APIs, a tiny base controller that wraps json_encode into a Response beats relying on implicit conversion.

Sub-routers as a composition tool. Because Router is a PSR-15 participant, you can mount one router inside another group, or keep a router per module and chain them — useful for splitting a large route file without a service provider abstraction.

Debugging and introspection. $router->getRoutes() gives you the registered collection; dumping it in a test or a routes:list-style command is the fastest way to see names, methods and patterns. $router->currentRoute() after a match exposes the matched Route (name, params, middleware) for logging.

Gotchas and Tips

  • No response factory, no string returns. If you construct Router without a PSR-17 factory (or without setting one), returning a string from a handler will fail. Pass a factory in the constructor and forget about it.
  • Trailing slashes are strict. FastRoute treats /posts and /posts/ as different patterns. Pick a convention, normalise in front-controller middleware, and don't be surprised by 404s during development.
  • 404 vs 405. A method mismatch is not a missing route — verify what status your stack emits for a POST to a GET-only path. If you need Laravel's 405 semantics, wrap the router and translate FastRoute's "allowed methods" result.
  • No route cache. Unlike Laravel's route:cache, the dispatcher is built per request. For high-traffic apps, wire FastRoute's cached dispatcher yourself, or accept the cost (it is small — measure before optimising).
  • Route names are global. Name prefixes on groups are a convention enforced by you, not by the router. Duplicate names silently overwrite; add a test that asserts name uniqueness if your app generates a lot of URLs.
  • Container is optional but load-bearing for controllers. Without one, Controller@method is instantiated with new, so any constructor dependency breaks. If you use controllers at all, pass a container.
  • Parameter injection is name-based. Renaming a controller parameter away from the route placeholder is a silent break. Type-hinting RouteParams avoids the coupling.
  • HEAD and OPTIONS are not free. HEAD requests generally don't match a GET route automatically, and CORS preflight is middleware's job. Register any() or explicit options() routes and add a CORS middleware if you serve browsers.
  • Middleware ordering surprises. Group middleware runs outermost regardless of where you attach it relative to route middleware; if auth must run before body parsing, put it on the group, not the route.
  • Immutable PSR-7 everywhere. Handlers returning a modified request, or middleware returning the original response instead of the one from $handler->handle(), is the most common bug in PSR-15 code — the router itself won't catch it.
  • Extension points worth knowing: the callable resolver (custom argument injection), the response factory (custom default responses), and the PSR-11 container (controller/middleware construction). These three cover almost every "I wish it did X" moment.
  • Community size is the real risk. At ~87 stars this is a small, agency-maintained package. The API is stable and the scope is deliberately narrow, but expect to read the source (it is a few hundred lines) rather than find a Stack Overflow answer. Vendoring discipline: pin a major version, and keep your own thin wrapper around Router so swapping to Slim, FastRoute directly, or Laravel later is a one-file change.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource