0

What middleware is — the pipeline pattern

Beginner5 min read·lv-07-001
interviewframework

Concept

Middleware is software that sits between the HTTP request and the application response, intercepting requests (and responses) to apply cross-cutting concerns: authentication, logging, rate limiting, CORS headers, compression, locale detection.

The pipeline pattern: Laravel routes requests through a pipeline of middleware before they reach a controller. Each middleware in the pipeline either passes the request to the next middleware ($next($request)), or short-circuits and returns its own response. After the controller returns, the response passes back through the middleware stack in reverse order.

Metaphor: Think of middleware as airport security layers. The request is a passenger. Each checkpoint (middleware) can: let the passenger through, search their bag and add a stamp (modify request/response), or turn them away (short-circuit with a 401/403/429). After the flight (controller runs), the passenger (response) passes back through checkpoints on the way out (you can modify responses here too).

Middleware kinds:

  • Request middleware: Inspect/modify request before passing to next.
  • Response middleware: Inspect/modify response after getting it from next.
  • Short-circuit middleware: Return a response without calling $next (auth failure, rate limit exceeded).
  • Wrapping middleware: Do something before AND after (transaction wrapping, request timing).

Laravel's built-in middleware: App\Http\Middleware\Authenticate (auth), VerifyCsrfToken, TrimStrings, ConvertEmptyStringsToNull, TrustProxies, PreventRequestsDuringMaintenance, and HTTP middleware kernel stack.

Code Example

php
<?php
// Middleware pipeline visualization

// Incoming request → [TrustProxies] → [ThrottleRequests] → [Authenticate] → Controller → Response
//                  ←                 ←                    ←                ←

// Minimal middleware structure
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ExampleMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // === BEFORE the controller runs ===
        // Inspect/modify the incoming request here

        $response = $next($request); // pass to next middleware (or controller)

        // === AFTER the controller runs ===
        // Inspect/modify the outgoing response here

        return $response;
    }
}

// Request-only middleware — add request context
class AddRequestId
{
    public function handle(Request $request, Closure $next): Response
    {
        $requestId = (string) \Illuminate\Support\Str::uuid();
        $request->headers->set('X-Request-ID', $requestId);
        return $next($request);
    }
}

// Response-only middleware — add response headers
class AddVersionHeader
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);
        $response->headers->set('X-API-Version', config('app.api_version'));
        return $response;
    }
}

// Short-circuit middleware — stop the request
class RequireHttps
{
    public function handle(Request $request, Closure $next): Response
    {
        if (!$request->secure() && app()->isProduction()) {
            return redirect()->secure($request->getRequestUri());
        }
        return $next($request);
    }
}