PHPackages                             meritum/http - 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. [HTTP &amp; Networking](/categories/http)
4. /
5. meritum/http

ActiveLibrary[HTTP &amp; Networking](/categories/http)

meritum/http
============

Module-first PSR-15 HTTP kernel for the Meritum ecosystem

1.0.0(yesterday)00MITPHPPHP ^8.4CI passing

Since Jun 8Pushed yesterdayCompare

[ Source](https://github.com/MeritumIO/http)[ Packagist](https://packagist.org/packages/meritum/http)[ RSS](/packages/meritum-http/feed)WikiDiscussions main Synced yesterday

READMEChangelogDependencies (11)Versions (2)Used By (0)

meritum/http
============

[](#meritumhttp)

Module-first PSR-15 HTTP kernel for the Meritum ecosystem.

Requirements
------------

[](#requirements)

- PHP 8.4+
- [`georgeff/kernel`](https://github.com/MikeGeorgeff/kernel) ^1.6

Installation
------------

[](#installation)

```
composer require meritum/http
```

Basic usage
-----------

[](#basic-usage)

```
use Georgeff\Kernel\Environment;
use Meritum\Http\HttpKernel;

$kernel = new HttpKernel(Environment::Production);

$kernel->addRoute('GET', '/', HomeHandler::class);

$kernel->boot();
$kernel->run();
```

`run()` resolves the incoming request from globals, passes it through the middleware pipeline, emits the response, calls `terminate()`, and shuts the kernel down.

Routing
-------

[](#routing)

### Registering routes

[](#registering-routes)

Routes must be registered before `boot()`. The handler can be a `RequestHandlerInterface` instance or a container service ID string.

```
$kernel->addRoute('GET', '/users', ListUsersHandler::class);
$kernel->addRoute(['GET', 'HEAD'], '/users/{id}', ShowUserHandler::class);
$kernel->addRoute('POST', '/users', CreateUserHandler::class);
```

`addRoute()` returns a `RouteInterface` for further configuration.

### Route arguments

[](#route-arguments)

FastRoute path parameters are available on the request as a route attribute:

```
use Meritum\Http\Routing\RouteInterface;

public function handle(ServerRequestInterface $request): ResponseInterface
{
    /** @var RouteInterface $route */
    $route = $request->getAttribute('__route__');

    $id = $route->getArgument('id');
}
```

### Route middleware

[](#route-middleware)

Middleware can be attached to individual routes and will run after the global stack, before the handler:

```
$kernel->addRoute('GET', '/admin', AdminHandler::class)
       ->addMiddleware(AuthMiddleware::class)
       ->addMiddleware(RateLimitMiddleware::class);
```

Middleware
----------

[](#middleware)

### Global middleware

[](#global-middleware)

Global middleware runs on every request, before route middleware:

```
$kernel->addMiddleware(LoggingMiddleware::class);
$kernel->addMiddleware(new CorsMiddleware());
```

Middleware can be a `MiddlewareInterface` instance or a container service ID string. Global middleware must be registered before `boot()`.

### Execution order

[](#execution-order)

```
global middleware → route middleware → handler

```

Exception handling
------------------

[](#exception-handling)

By default, exceptions thrown by the middleware pipeline propagate out of `handle()`. To catch them and return a response, register an `ExceptionHandlerInterface` implementation in the container before boot:

```
use Meritum\Http\Exception\ExceptionHandlerInterface;

$kernel->define(ExceptionHandlerInterface::class, fn() => new MyExceptionHandler())->share();
$kernel->boot();
```

```
use Meritum\Http\Exception\ExceptionHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final class MyExceptionHandler implements ExceptionHandlerInterface
{
    public function handle(\Throwable $e, ServerRequestInterface $request): ResponseInterface
    {
        // build and return an error response
    }
}
```

The exception handler can check `$e instanceof HttpExceptionInterface` to distinguish HTTP errors from unexpected exceptions and access the status code and title:

```
use Meritum\Http\Exception\HttpExceptionInterface;

if ($e instanceof HttpExceptionInterface) {
    $status = $e->getStatusCode(); // e.g. 404
    $title  = $e->getTitle();      // e.g. 'Not Found'
}
```

HTTP exceptions
---------------

[](#http-exceptions)

The package provides a base exception class and two concrete exceptions thrown by the router:

ClassStatus`HttpException`500`NotFoundHttpException`404`MethodNotAllowedHttpException`405All implement `HttpExceptionInterface` which exposes `getStatusCode()`, `getTitle()`, and `getRequest()`.

`MethodNotAllowedHttpException` exposes the allowed methods via the `$allowedMethods` property:

```
use Meritum\Http\Exception\MethodNotAllowedHttpException;

if ($e instanceof MethodNotAllowedHttpException) {
    $allowed = $e->allowedMethods; // ['GET', 'HEAD']
}
```

Custom HTTP exceptions can extend `HttpException` and override the `$status` and `$title` properties:

```
use Meritum\Http\Exception\HttpException;

final class UnprocessableEntityException extends HttpException
{
    protected string $title = 'Unprocessable Entity';
    protected int $status = 422;
}
```

Terminating callbacks
---------------------

[](#terminating-callbacks)

Callbacks registered with `onTerminating()` run after the response has been emitted. They receive the request, response, and kernel:

```
$kernel->onTerminating(function (
    ServerRequestInterface $request,
    ResponseInterface $response,
    KernelInterface $kernel
): void {
    // flush logs, close connections, etc.
});
```

Callbacks must be registered before `boot()`. By default, the kernel registers one terminating callback that calls `shutdown()`.

Handling requests directly
--------------------------

[](#handling-requests-directly)

`handle()` can be called directly instead of going through `run()`, which is useful for testing or custom request/response lifecycles:

```
$kernel->boot();

$response = $kernel->handle($request);

// emit, then terminate
$kernel->terminate($request, $response);
```

Using modules
-------------

[](#using-modules)

Routes, middleware, service definitions, and terminating callbacks can be registered inside a `ModuleInterface` implementation:

```
use Georgeff\Kernel\Module\ModuleInterface;
use Meritum\Http\HttpKernelInterface;

final class ApiModule implements ModuleInterface
{
    public function register(KernelInterface $kernel): void
    {
        assert($kernel instanceof HttpKernelInterface);

        $kernel->addRoute('GET', '/api/users', ListUsersHandler::class);
        $kernel->addMiddleware(ApiAuthMiddleware::class);

        $kernel->define(ListUsersHandler::class, fn() => new ListUsersHandler())->share();
    }
}
```

```
$kernel->addModule(new ApiModule());
$kernel->boot();
$kernel->run();
```

License
-------

[](#license)

MIT

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

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

Unknown

Total

1

Last Release

1d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/c8147ce1d901e9fa2ec95d6408e5862025211f9ae60131e41fb115a5a0916ce4?d=identicon)[georgeff](/maintainers/georgeff)

---

Top Contributors

[![MikeGeorgeff](https://avatars.githubusercontent.com/u/6169468?v=4)](https://github.com/MikeGeorgeff "MikeGeorgeff (1 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/meritum-http/health.svg)

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

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.8k19.1M1.7k](/packages/cakephp-cakephp)[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

7.9k1.1B3.7k](/packages/guzzlehttp-psr7)[tempest/framework

The PHP framework that gets out of your way.

2.2k31.1k11](/packages/tempest-framework)[flarum/core

Delightfully simple forum software.

261.4M2.2k](/packages/flarum-core)[mezzio/mezzio-authentication-oauth2

OAuth2 (server) authentication middleware for Mezzio and PSR-7 applications.

28545.4k3](/packages/mezzio-mezzio-authentication-oauth2)[mimmi20/browser-detector

Library to detect Browsers and Devices

48156.1k4](/packages/mimmi20-browser-detector)

PHPackages © 2026

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