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

Psr7 Middlewares Laravel Package

oscarotero/psr7-middlewares

A collection of PSR-7 middleware for PHP, including authentication, caching, CORS, HTTPS, and routing. Works with any PSR-7 compatible framework or application.

Deep Wiki
Context7

Getting Started

  • Install with Composer: composer require oscarotero/psr7-middlewares. Because the package is archived and last released in 2017, pin the version, check PHP/PSR-7 compatibility, and audit transitive dependencies before using it in a maintained app.
  • Understand the contract first: these are double-pass PSR-7 middleware — invokable objects with the shape ($request, $response, $next) returning a ResponseInterface. They are not PSR-15 process() middleware. A middleware may short-circuit by returning a response, or call $next($request, $response) and modify the downstream response.
  • Look first at src/Middleware/ for the available middleware classes, src/Middleware.php for the static factory, and the tests for each middleware. The tests are the most reliable documentation for config array keys and request-attribute names.
  • Use any compatible double-pass dispatcher — Relay, older Expressive/Stratigility, Slim 3, or a small custom queue dispatcher. The package does not replace your router or HTTP kernel.

A minimal first stack:

use Oscarotero\Psr7Middlewares\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

$stack = [
    Middleware::responseTime(),
    Middleware::clientIp(['10.0.0.0/8']),
    Middleware::errorHandler(),
    Middleware::cors([
        'origins' => ['https://app.example.com'],
        'methods' => ['GET', 'POST', 'OPTIONS'],
        'headers' => ['Content-Type', 'Authorization'],
    ]),
    Middleware::payload(),
    Middleware::formatNegotiator(),
    function (ServerRequestInterface $request, ResponseInterface $response, callable $next) {
        $response->getBody()->write(json_encode([
            'ip' => $request->getAttribute('client-ip'),
            'format' => $request->getAttribute('format'),
        ]));

        return $response->withHeader('Content-Type', 'application/json');
    },
];

Then dispatch with a queue runner:

$dispatch = function (
    ServerRequestInterface $request,
    ResponseInterface $response,
    array $stack
) use (&$dispatch) {
    $middleware = array_shift($stack);

    if ($middleware === null) {
        return $response;
    }

    return $middleware($request, $response, function ($request, $response) use (&$dispatch, $stack) {
        return $dispatch($request, $response, $stack);
    });
};

$response = $dispatch($request, $response, $stack);

Emit the final response with Diactoros/Laminas, Guzzle, or whatever PSR-7 implementation you already use.

Implementation Patterns

  • Order the stack deliberately. Put ErrorHandler/Whoops outermost so exceptions from all inner middleware are caught. Put Https, ClientIp, and proxy handling early. Put Cors before authentication so preflight OPTIONS requests are not rejected. Put Payload and negotiation before the handler. Response-transformers wrap downstream and run again after $next.
  • Use the static factory as a declarative stack builder. Middleware::cors(), Middleware::payload(), Middleware::formatNegotiator(), etc. return configured instances. Build named stacks — api, web, admin — from config rather than scattering new calls.
  • Treat request attributes as the integration contract. Middleware communicate by attaching values to the request: client IP, parsed payload, negotiated format/language, session, request ID. Read these in your final handler with $request->getAttribute(...); do not reach into superglobals. Document the attribute names you depend on because they are informal contracts.
  • Combine auth with network controls. Use basic/digest authentication with Firewall, ClientIp, and Https. Return 401 with WWW-Authenticate for unauthenticated requests and 403 for authenticated-but-forbidden requests. Keep trusted-proxy configuration consistent with your edge/load balancer.
  • Handle CORS preflight explicitly. Configure allowed origins, methods, and headers, and make sure OPTIONS short-circuits before auth and routing. Emit Vary: Origin when reflecting an origin. Never combine credentialed CORS with Access-Control-Allow-Origin: *.
  • Parse payloads once, then validate. Use Payload to parse JSON/form bodies into an attribute, then validate in your handler or a dedicated validation middleware. Use FormatNegotiator and LanguageNegotiator to select response format/language, and set matching Content-Type and Vary: Accept, Accept-Language headers.
  • Use logging/request-ID middleware at the boundary. ResponseTime, AccessLog, and Uuid are useful for correlating a request across the stack. Decide whether you want to log cached and error responses, and place the logger accordingly.
  • Layer response concerns. RemoveHeaders, Csp, Minify, and redirect/trailing-slash middleware are best kept near the edge of the stack. Keep business logic in a final handler; middleware should remain cross-cutting.
  • In Laravel, bridge at the boundary rather than replacing the HTTP kernel. Laravel uses Symfony HTTP Foundation, not PSR-7. For a Laravel route that must run a PSR-7 pipeline, convert the Laravel request to a PSR-7 request, run the stack, then convert the PSR-7 response back to a Laravel/Symfony response. For a larger PSR-7 surface, run the stack as a separate service or a dedicated PSR-7 kernel. Do not expect these middleware to register directly as Laravel middleware.
  • Test middleware in isolation. Build PSR-7 requests/responses with Diactoros or Guzzle, invoke the middleware with a recording $next, and assert request attributes, status codes, and headers. Test stack order with a middleware that records entry/exit.

Gotchas and Tips

  • Archived and unmaintained. Last release was 2017. There are no security patches, and newer PSR-7/PSR-15 interfaces may conflict. Use it for legacy PSR-7 stacks or isolated internal services; for new code, prefer maintained PSR-15 middleware packages or Laravel-native middleware.
  • Not PSR-15 compatible. The double-pass signature does not plug into PSR-15 dispatchers. If your framework expects process(ServerRequestInterface, RequestHandlerInterface), you need an adapter or a compatibility dispatcher. Do not mix the two contracts in one stack without wrapping.
  • Laravel is not PSR-7-native. Bridging Symfony requests to PSR-7 introduces conversion costs and edge cases around streams, uploaded files, cookies, headers, and sessions. For normal Laravel routes, native middleware (TrustProxies, CORS, auth, throttle, cache headers) is simpler and faster.
  • Middleware order changes behavior. CORS after auth breaks preflight. Error handling inside auth leaves auth exceptions uncaught. Client-IP resolution after rate limiting produces wrong limits. Write an order test rather than relying on memory.
  • Trusted proxies are a security boundary. Only trust X-Forwarded-For/X-Forwarded-Proto from known proxies. Blindly trusting client headers allows IP spoofing and HTTPS-detection bypass. Keep this configuration aligned with your load balancer and Laravel TrustProxies.
  • Streams are mutable and easy to corrupt. Rewind before emitting. Do not echo from middleware. Do not assume getBody() is a string; use stream factories or withBody(). Avoid writing to the same body twice when wrapping downstream responses.
  • Payload parsing consumes the body. Parse once and store the result in a request attribute. Handle malformed JSON and empty bodies explicitly, usually via the outer error handler returning 400.
  • Caching needs a correct key. Include method, URI, and every Vary dimension: Accept, Accept-Language, Origin, and Authorization where relevant. Never cache authenticated or personalized responses unless the key includes the user/tenant. Invalidate on writes.
  • Sessions are coupled to PHP. PhpSession assumes PHP session behavior: locking, headers, and global state. It is a poor fit for stateless APIs and can conflict with Laravel’s session handling. Prefer an explicit session service in Laravel.
  • Whoops is development-only. Do not ship Whoops error pages in production. Use ErrorHandler to map exceptions to JSON or HTML responses, log them, and keep it outermost in the stack.
  • Debug by inspecting attributes and headers. Add a temporary logging middleware at the top and bottom of the stack, dump request attributes and response status/headers, and compare against the package tests for exact attribute and config keys.
  • Extension point: write the same callable shape. Custom middleware is just an invokable class or closure with ($request, $response, $next). Compose or wrap existing middleware rather than editing vendor code. If you need long-term maintenance, fork and pin the package, or migrate the stack to PSR-15 equivalents.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core