PHPackages                             colossal/colossal-router - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. colossal/colossal-router

ActiveLibrary[API Development](/categories/api)

colossal/colossal-router
========================

A simple router implementation utilizing the PSR-15 standardized interfaces.

v1.0.3(2y ago)016MITPHPPHP ^8.0

Since Jun 1Pushed 2y ago1 watchersCompare

[ Source](https://github.com/colossalg/Colossal-Router)[ Packagist](https://packagist.org/packages/colossal/colossal-router)[ Docs](https://github.com/colossalg/Colossal-Router)[ RSS](/packages/colossal-colossal-router/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (7)Versions (5)Used By (0)

Colossal-Router
===============

[](#colossal-router)

A simple router implementation utilizing the PSR-15 standardized interfaces.

Creating the Router
-------------------

[](#creating-the-router)

```
// ---------------------------------------------------------------------------- //
// Creating the router is trivial, the constructor takes no arguments.          //
// Configuration is performed via the method calls on an instance.              //
// ---------------------------------------------------------------------------- //

use Colossal\Routing\Router;
use Psr\Http\Message\{  // These will always be required.
    ResponseInterface,
    ServerRequestInterface
};

$router = new Router();

// ...

$router->processRequest($request);
```

Adding Routes
-------------

[](#adding-routes)

```
// ---------------------------------------------------------------------------- //
// There are two methods to add routes:                                         //
//      - Registering a closure     - via the Router::addRoute() method.        //
//      - Registering a controller  - via the Router::addController() method.   //
//                                                                              //
// (The optional middleware parameters of these methods are covered in the      //
// middleware section below.)                                                   //
//                                                                              //
// To register a closure the following must be specified:                       //
//      - The HTTP method for the route.                                        //
//      - The PCRE pattern for the route.                                       //
//      - The handler for the route (this is the closure).                      //
//                                                                              //
// To register a controller, for each method intended to be registered          //
// as an end-point, the following must specified via a Route attribute:         //
//      - The HTTP method for the route.                                        //
//      - The PCRE pattern for the route.                                       //
//                                                                              //
// Behind the scenes what will happen is that each method registered as an      //
// end-point will be wrapped in a closure which will call the method on an      //
// instance of the controller. The HTTP method, PCRE pattern, and the closure   //
// together will then be registered via Router::addRoute().                     //
//                                                                              //
// All route handlers, whether they are created via a passed closure or a       //
// closure created from a contoller's method, must return an instance of a      //
// ResponseInterface (see the PSR-7 and PSR-15 standards for more info).        //
//                                                                              //
// (The parameters of route handlers are covered in the route parameter section //
// below.)                                                                      //
// ---------------------------------------------------------------------------- //

use Colossal\Routing\Router;
use Psr\Http\Message\{
    ResponseInterface,
    ServerRequestInterface
};

final class PostController
{
    // This route will match any GET requests to /posts or /posts/
    #[Route(method: "GET", pattern: "%^/posts/?$%")]
    public function getPosts(): ResponseInterface
    {
        // Perform request, create response and return.
        // ...
    }

    // This route will match any POST requests to /posts or /posts/
    #[Route(method: "POST", pattern: "%^/posts/?$%")]
    public function setPosts(): ResponseInterface
    {
        // Perform request, create response and return.
        // ...
    }
}

$router = new Router();

// This route will match any GET requests to /queue or /queue/
$router->addRoute("GET", "%^/queue/?$%", function (): ResponseInterface {
    // Perform request, create response and return.
    // ...
});

// This route will match any POST requests to /queue or /queue/
$router->addRoute("POST", "%^/queue/?$%", function (): ResponseInterface {
    // Perform request, create response and return.
    // ...
});

// Register the controller. All of the reflection magic happens behind the scenes.
$router->addController(UserController::class);

// ...

$router->processRequest($request);
```

Route Parameters
----------------

[](#route-parameters)

```
// ---------------------------------------------------------------------------- //
// To provide routes with parameters:                                           //
//      - Create a named capture group in the route's PCRE pattern.             //
//      - Add a parameter to the closure/controller method with:                //
//          - An identical name to the capture group.                           //
//          - One of the following types:                                       //
//              - int                                                           //
//              - string                                                        //
//                                                                              //
// There is one exception to above. The route may take an argument with type    //
// ServerRequestInterface in addition to any other route parameters. In this    //
// instance no capture group must be specified in the route's PCRE pattern.     //
// ---------------------------------------------------------------------------- //

use Colossal\Routing\Router;
use Psr\Http\Message\{
    ResponseInterface,
    ServerRequestInterface
};

$router = new Router();

// This route will match any GET requests to /users/ or /users//
//  will be:
//      - Extracted from the path.
//      - Cast to an int.
//      - Passed as the $id param of the route handler.
$router->addRoute("GET", "%^/users/(?\d+)/?$%", function (int $id): ResponseInterface {
    echo "User id = $id";
    // Perform request, create response and return.
    // ...
});

// This route will match any POST requests to /users//profile or /users//profile/
// $request will be the ServerRequestInterface that the router was dispatched to handle.
//  will be:
//      - Extracted from the path.
//      - Cast to an int.
//      - Passed as the $id param of the route handler.
$router->addRoute(
    "POST",
    "%^/users/(?\d+)/profile/?$%",
    function (ServerRequestInterface $request, int $id): ResponseInterface {
        echo "User id = $id";
        // Perform request, create response and return.
        // Ex. Parse JSON from the body of $request.
        // ...
    }
);

// ...

$router->processRequest($request);
```

Sub-Routers
-----------

[](#sub-routers)

```
// ---------------------------------------------------------------------------- //
// Sub-routers are supported. The primary driving force for this is the ability //
// to register additional middleware on the sub-routers.                        //
//                                                                              //
// Ex.                                                                          //
//      Router A (router-a)                                                     //
//      - Middleware    (middleware-a)                                          //
//      - Fixed start   ("")                                                    //
//      - Routes        (/index, /about, etc...)                                //
//      - Sub-routers   (router-b)                                              //
//                                                                              //
//      Router B (router-b)                                                     //
//      - Middleware    (middleware-b)                                          //
//      - Fixed start   ("/api")                                                //
//      - Routes        ("/posts")                                              //
//      - Sub-routers   (empty)                                                 //
//                                                                              //
// A request to /api/posts will match router-b and each of the following will   //
// be executed in order:                                                        //
//      - middleware-a                                                          //
//      - middleware-b                                                          //
//      - The handler for the /api/posts route.                                 //
//                                                                              //
// Any requests to /index, /about will only invoke middleware-a.                //
//                                                                              //
// Each sub-router should be assigned a "fixed start". The fixed start is what  //
// indicates whether a sub-router should be transfered responsibility for the   //
// routing of a request and its use is simple:                                  //
//      - If the routing path starts with the fixed string, the sub-router is   //
//        assumed to be able to handle the request.                             //
//                                                                              //
// The fixed start is not a PCRE, just an ordinary string.                      //
// ---------------------------------------------------------------------------- //

use Colossal\Routing\Router;
use Psr\Http\Message\{
    ResponseInterface,
    ServerRequestInterface
};

$router = new Router();

$subRouter = new Router();
$subRouter->setFixedStart("/api");
// Register routes with sub-router, etc...
$router->addSubRouter($subRouterA);

// ...
```

Route Resolution
----------------

[](#route-resolution)

```
// ---------------------------------------------------------------------------- //
// When resolving a route:                                                      //
//      - Sub-routers are examined first.                                       //
//      - Routes are examined second.                                           //
//                                                                              //
// The sub-routers are examined descending order of the length of their fixed   //
// start string. If the routing path matches the fixed start string of a sub-   //
// router then that sub-router takes ownership of the request by:               //
//      - Stripping it's fixed start string from the start of the request path. //
//      - Checking its own sub-routers and routes for a match.                  //
//                                                                              //
// The routes are examined in order that they were registered with the router   //
// checking whether both:                                                       //
//      - The route's HTTP method matches the request method.                   //
//      - The route's PCRE pattern matches the request URI path.                //
//                                                                              //
// Once a route satisfying the above is found, the route's handler is called    //
// for the request and the resulting response returned.                         //
// ---------------------------------------------------------------------------- //

use Colossal\Routing\Router;
use Psr\Http\Message\{
    ResponseInterface,
    ServerRequestInterface
};

$router = new Router();

$subRouterA = new Router();
$subRouterA->setFixedStart("/api");
// Register routes with sub-router A, etc...
$router->addSubRouter($subRouterA);

$subRouterB = new Router();
$subRouterB->setFixedStart("/api/posts");
// Register routes with sub-router B, etc...
$router->addSubRouter($subRouterB);

$router->addRoute("GET", "%^/page/(A|B)$%, function (): ResponseInterface {
    echo "Route 1";
    // Perform request, create response and return.
    // ...
});
$router->addRoute("GET", "%^/page/(B|C)$%, function (): ResponseInterface {
    echo "Route 2";
    // Perform request, create response and return.
    // ...
});
$router->addRoute("GET", "%^/page/(C|D)$%, function (): ResponseInterface {
    echo "Route 3";
    // Perform request, create response and return.
    // ...
});

// Any requests starting with /api but not /api/posts will be handled by sub-router A.
// Any requests starting with /api/posts will be handled by sub-router B.

// Any other posts will be checked against the routes of $router.
// A GET request with path /page/B will echo "Route 1".
// A GET request with path /page/C will echo "Route 2".

// ...

$router->processRequest($request);
```

Middleware
----------

[](#middleware)

```
// ---------------------------------------------------------------------------- //
// Middleware implementing the PSR-15 MiddlewareInterface may be registered     //
// with the router, routes and controllers.                                     //
//                                                                              //
// Middleware is only executed once a matching route is found. All middleware   //
// of the routers comprising the path from the base router to the matching      //
// route, as well as the route's middleware, will be executed.                  //
// ---------------------------------------------------------------------------- //

use Colossal\Routing\Router;
use Psr\Http\Message\{
    ResponseInterface,
    ServerRequestInterface
};
use Psr\Http\Server\{
    MiddlewareInterface,
    RequestHandlerInterface
};

final class DummyMiddleware implements MiddlewareInterface
{
    // ...

    public function process(
        ServerRequestInterface $request,
        RequesthandlerInterface $handler
    ): ResponseInterace {
        // Perform request, create response and return.
        // ...
    }

    // ...
}

final class DummyController
{
    #[Route(method: "GET", pattern: "%^/dummy/?$%")]
    public function getDummy(): ResponseInterface
    {
        // Perform request, create response and return.
        // ...
    }

    #[Route(method: "POST", pattern: "%^/dummy/?$%")]
    public function setDummy(): ResponseInterface
    {
        // Perform request, create response and return.
        // ...
    }
}

$router = new Router();

// Register middleware for the router.
$router->setMiddleware(new DummyMiddleware());

// Register middleware for a single route.
$router->addRoute(
    "GET",
    "%^/queue/?$%",
    function (): ResponseInterface {
        // Perform request, create response and return.
        // ...
    },
    new DummyMiddleware()
);

// Register middleware for all routes of the controller.
$router->addController(DummyController::class, new DummyMiddleware());

$router->processRequest($request);
```

Development Tips
----------------

[](#development-tips)

### Running PHPUnit Test Suites

[](#running-phpunit-test-suites)

Run the PHPUnit test suites with the following command:

```
>> .\vendor\bin\phpunit
```

To additionally print the test coverage results to stdout run the following command:

```
>> .\vendor\bin\phpunit --coverage-html="coverage"
```

### Running PHPStan Code Quality Analysis

[](#running-phpstan-code-quality-analysis)

Run the PHPStan code quality analysis with the following command:

```
>> .\vendor\bin\phpstan --configuration=phpstan.neon --xdebug
```

### Running PHP Code Sniffer Code Style Analysis

[](#running-php-code-sniffer-code-style-analysis)

Run the PHP Code Sniffer code style analysis with the following commands:

```
>> .\vendor\bin\phpcs --standard=phpcs.xml src
>> .\vendor\bin\phpcs --standard=phpcs.xml test
```

To fix automatically resolve issues found by PHP Code Sniffer run the following commands:

```
>> .\vendor\bin\phpcbf --standard=phpcs.xml src
>> .\vendor\bin\phpcbf --standard=phpcs.xml test
```

###  Health Score

23

—

LowBetter than 27% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity6

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~52 days

Total

4

Last Release

916d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/0d2a935d24a37f2255e4aba33f327f6d9f9e91b1063ffcd3a51ce46ea841dd58?d=identicon)[colossalg](/maintainers/colossalg)

---

Top Contributors

[![colossalg](https://avatars.githubusercontent.com/u/39691679?v=4)](https://github.com/colossalg "colossalg (32 commits)")

---

Tags

routerpsr-15

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/colossal-colossal-router/health.svg)

```
[![Health](https://phpackages.com/badges/colossal-colossal-router/health.svg)](https://phpackages.com/packages/colossal-colossal-router)
```

###  Alternatives

[thecodingmachine/graphqlite

Write your GraphQL queries in simple to write controllers (using webonyx/graphql-php).

5723.1M30](/packages/thecodingmachine-graphqlite)[league/route

Fast routing and dispatch component including PSR-15 middleware, built on top of FastRoute.

6633.1M116](/packages/league-route)[sunrise/http-router

A powerful solution as the foundation of your project.

16249.8k10](/packages/sunrise-http-router)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
