monkeyscloud/monkeyslegion-http

High-performance PSR-7/PSR-15/PSR-17 HTTP message implementations, middleware stack, and SAPI emitter for the MonkeysLegion framework.

Maintainers

Package info

github.com/MonkeysCloud/MonkeysLegion-Http

Homepage

Issues

pkg:composer/monkeyscloud/monkeyslegion-http

Transparency log

Fund package maintenance!

monkeyscloud

Statistics

Installs: 3 144

Dependents: 9

Suggesters: 0

Stars: 1

2.2.0 2026-08-16 16:48 UTC

README

High-performance PSR-7 / PSR-15 / PSR-17 HTTP library for the MonkeysLegion framework โ€” a complete HTTP message implementation, a production-ready middleware stack, and a SAPI emitter. Built natively for PHP 8.4.

PHP Version Latest Stable Version License: MIT CS: PSR-12 PHPStan Level 9 CI Total Downloads

โœจ Features

  • ๐Ÿ“ฆ PSR-7 messages โ€” immutable ServerRequest, Response, JsonResponse, Stream, Uri (zero external message dependency)
  • ๐Ÿงฉ PSR-15 middleware โ€” 14 production-ready middleware components
  • ๐Ÿญ PSR-17 factory โ€” HttpFactory for every message type
  • ๐Ÿš€ O(1) dispatcher โ€” cursor-based MiddlewareDispatcher, no array_shift overhead
  • ๐Ÿ”Œ Pipeable pipeline โ€” Express-style CoreRequestHandler with pipe() and lock()
  • ๐ŸŒ Full CORS โ€” wildcard *, subdomain patterns (https://*.example.com), credentials, preflight caching
  • ๐Ÿ›ก๏ธ Security headers โ€” strict / relaxed / api presets (CSP, HSTS, frame-ancestors, โ€ฆ)
  • ๐Ÿ”‘ Auth + CSRF โ€” timing-safe bearer auth with optional JWT decoding, stateless double-submit CSRF
  • โฑ๏ธ Rate limiting โ€” sliding-window limiter with PSR-16 cache support and per-route overrides
  • ๐Ÿ“ค SAPI emitter โ€” chunked streaming emitter with Content-Length injection
  • ๐Ÿ†˜ Error handling โ€” OOM-safe global handler with PSR-3 logging and pluggable renderers
  • ๐Ÿงฐ Helper functions โ€” response(), json(), redirect(), html(), and more
  • ๐Ÿงช PHPStan Level 9 โ€” maximum static analysis rigor
  • ๐Ÿ†• PHP 8.4 native โ€” final classes, readonly properties, property hooks, match expressions

๐Ÿ“ฆ Installation

composer require monkeyscloud/monkeyslegion-http

Requires PHP 8.4+ and psr/http-message ^2.0 (installed automatically).

๐Ÿš€ Quick Start

use MonkeysLegion\Http\Message\ServerRequest;
use MonkeysLegion\Http\Message\JsonResponse;
use MonkeysLegion\Http\Emitter\SapiEmitter;

// Build request from PHP superglobals
$request = ServerRequest::fromGlobals();

// Convenience accessors
$email = $request->input('user.email');   // Dot-notation body access
$token = $request->bearerToken();          // Authorization: Bearer ...
$ip    = $request->ip();                   // Client IP
$agent = $request->userAgent();            // User-Agent header
$hash  = $request->fingerprint();          // SHA-256 request fingerprint

// Create a JSON response and emit it
$response = new JsonResponse(['status' => 'ok'], 200);
(new SapiEmitter())->emit($response);

Middleware stack

use MonkeysLegion\Http\MiddlewareDispatcher;
use MonkeysLegion\Http\CoreRequestHandler;
use MonkeysLegion\Http\Middleware\{
    RequestIdMiddleware,
    SecurityHeadersMiddleware,
    CorsMiddleware,
    RateLimitMiddleware,
    AuthMiddleware,
};

$dispatcher = new MiddlewareDispatcher(
    middlewareStack: [
        new RequestIdMiddleware(),
        new SecurityHeadersMiddleware('strict'),
        new CorsMiddleware(allowedOrigins: ['https://app.example.com']),
        new RateLimitMiddleware(limit: 100, window: 60),
        new AuthMiddleware(requiredToken: getenv('API_TOKEN')),
    ],
    finalHandler: new CoreRequestHandler($router),
);

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

๐Ÿ“‹ API Reference

ServerRequest

$email = $request->input('user.email', 'default@example.com'); // dot-notation
$all   = $request->all();                                      // all parsed fields
$only  = $request->only(['email', 'password']);                // subset of fields

$request->isJson();     // Expects JSON?
$request->isSecure();   // HTTPS?
$request->isAjax();     // XMLHttpRequest?
$request->isMethod('POST');

JsonResponse

use MonkeysLegion\Http\Message\JsonResponse;

$response = (new JsonResponse($data))->withEnvelope(message: 'Success');

$paginated = (new JsonResponse($items))
    ->withPagination(page: 1, perPage: 25, total: 100);
// { status, message, data, meta: { pagination: { total, page, per_page, last_page, has_more } } }

CORS Middleware

use MonkeysLegion\Http\Middleware\CorsMiddleware;

// Allow every origin (no credentials) โ†’ Access-Control-Allow-Origin: *
$cors = new CorsMiddleware();

// Allow specific origins
$cors = new CorsMiddleware(allowedOrigins: ['https://app.example.com']);

// '*' anywhere in the list allows every origin
$cors = new CorsMiddleware(allowedOrigins: ['https://api.example.com', '*']);

// Subdomain wildcard patterns
$cors = new CorsMiddleware(allowedOrigins: ['https://*.example.com']);

// Full configuration with credentials (origin is reflected, never '*')
$cors = new CorsMiddleware(
    allowedOrigins:   ['https://app.example.com'],
    allowedMethods:   ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
    allowedHeaders:   ['Content-Type', 'Authorization', 'X-Request-Id'],
    exposedHeaders:   ['X-Request-Id', 'X-Response-Time'],
    allowCredentials: true,
    maxAge:           3600,
);

โš ๏ธ Per the CORS specification, Access-Control-Allow-Origin: * cannot be combined with credentials. When allowCredentials is true, the middleware echoes the requesting origin instead.

Rate Limiter

use MonkeysLegion\Http\Middleware\RateLimitMiddleware;

$limiter = new RateLimitMiddleware(
    cache:   $psr16Cache,   // PSR-16 cache (Redis/Memcached) โ€” falls back to in-memory
    limit:   100,           // Requests per window
    window:  60,            // Window duration in seconds
);

// Per-route override via request attribute:
// $request = $request->withAttribute('rate_limit', ['limit' => 10, 'window' => 60]);

Security Headers

use MonkeysLegion\Http\Middleware\SecurityHeadersMiddleware;

$strict  = new SecurityHeadersMiddleware('strict');   // Production APIs (CSP, HSTS, โ€ฆ)
$relaxed = new SecurityHeadersMiddleware('relaxed');  // Development
$api     = new SecurityHeadersMiddleware('api');      // API-optimized (no CSP)

$custom = new SecurityHeadersMiddleware('strict', [
    'Content-Security-Policy' => "default-src 'self'",
]);

Auth Middleware

use MonkeysLegion\Http\Middleware\AuthMiddleware;

$auth = new AuthMiddleware(
    requiredToken: getenv('API_TOKEN'),
    publicPaths:   ['/health', '/login'],
    jwtDecoder:    fn (string $token) => JWT::decode($token, $key), // optional
);

Error Handler

use MonkeysLegion\Core\Error\ErrorHandler;
use MonkeysLegion\Http\Error\Renderer\JsonErrorRenderer;

$handler = new ErrorHandler(debug: false);
$handler->useRenderer(new JsonErrorRenderer());
$handler->useLogger($psrLogger);
$handler->register();

Features: OOM protection via reserved memory, recursive-exception guards, nested-failure fallback renderers (HTML/JSON/plain text), and PSR-3 logging.

PSR-17 Factory

use MonkeysLegion\Http\Factory\HttpFactory;

$factory = new HttpFactory();

$response = $factory->createResponse(200, 'OK');
$stream   = $factory->createStream('Hello');
$uri      = $factory->createUri('https://example.com/api');
$request  = $factory->createServerRequest('GET', $uri);

SAPI Emitter

use MonkeysLegion\Http\Emitter\SapiEmitter;

$emitter = new SapiEmitter(chunkSize: 8192);
$emitter->emit($response);
  • Auto-injects Content-Length when the body size is known
  • Guards against headers_sent() โ€” throws instead of silently corrupting output
  • Skips the body for 204/304 and aborts on dropped connections

Helper Functions

$r = response('Hello World', 200, ['X-Custom' => 'value']); // text
$r = json(['status' => 'ok']);                               // JSON
$r = jsonSuccess($data, 'User created', 201);                // { status, message, data }
$r = jsonError('Validation failed', 422);                    // { status, message }
$r = redirect('/dashboard', 302);                            // Location header
$r = html('<h1>Hello</h1>');                                 // HTML

๐Ÿง‘โ€๐Ÿ’ป Development

# Run all quality checks (code style + static analysis + tests)
composer check

# Or individually
composer test        # PHPUnit (unit tests)
composer phpstan     # PHPStan Level 9
composer cs-check    # PSR-12 code style (dry run)
composer cs-fix      # Auto-fix code style
composer infection   # Mutation testing (MSI โ‰ฅ 70%)

๐Ÿงช Testing & Quality Gates

  • Unit tests โ€” tests/Unit/, no external services (composer test)
  • Integration tests โ€” real HTTP through php -S + Redis-backed rate limiting, gated behind RUN_INTEGRATION_TESTS=1
  • Mutation testing โ€” Infection with MSI โ‰ฅ 70% and Covered MSI โ‰ฅ 71% (composer infection)
  • Static analysis โ€” PHPStan Level 9, zero errors
  • Code style โ€” PSR-12 via PHP-CS-Fixer

Run everything with one command:

composer quality-report

Integration tests run in CI against a Redis service container (see .github/workflows/ci.yml). Locally:

composer test:integration:docker

See TESTING.md for the complete testing guide.

๐Ÿ“„ Requirements

  • PHP 8.4+
  • psr/http-message ^2.0 ยท psr/http-server-middleware ^1.0 ยท psr/http-server-handler ^1.0 ยท psr/http-factory ^1.1
  • psr/simple-cache ^3.0 โ€” for RateLimitMiddleware shared storage

Optional

  • psr/log ^3.0 โ€” PSR-3 logging for ErrorHandler and LoggingMiddleware

๐Ÿ“œ License

MIT โ€” see LICENSE.