Middleware Implementation
How to Implement Middleware in Slim 4 Framework?
Section titled “How to Implement Middleware in Slim 4 Framework?”There are two main ways to implement middleware in Slim 4 Framework:
- Class-Based Middleware (PSR-15, recommended way to implement middleware)
- Function-Based Middleware (Closure-Based)
<?php
use Psr\Http\Message\ResponseInterface;use Psr\Http\Message\ServerRequestInterface;use Psr\Http\Server\RequestHandlerInterface;
$app = AppFactory::create();
$middleware = function (ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
    // Run some code before the request is handled.
    // Pass control to the next middleware or route handler.    $response = $handler->handle($request);
    // Run some code after the request is handled.    $response = $response->withHeader('X-Custom-Header', 'value');
    return $response;};
// Add the middleware to the application$app->add($middleware);Implementing Class-Based Middleware (PSR-15)
Section titled “Implementing Class-Based Middleware (PSR-15)”PSR-15 is the PHP Standard Recommendation for HTTP middleware. It provides a standardized interface that makes middleware portable and reusable across different applications and frameworks (e.g. Slim 4 Framework, Symfony, Laravel, etc.).
What is PSR-15?
Section titled “What is PSR-15?”PSR-15 defines how middleware should be structured:
- Middleware interface: For processing requests/responses
- Request handler interface: For handling the request
- Standardized method signatures: Ensures compatibility
Benefits of PSR-15:
- Code reusability across projects.
- Clear, predictable structure.
- Industry best practice.
- Better IDE support and type hinting.
Step-by-Step: Creating PSR-15 Middleware
Section titled “Step-by-Step: Creating PSR-15 Middleware”Step 1: Understand the Required Interface
Section titled “Step 1: Understand the Required Interface”Your middleware class must implement Psr\Http\Server\MiddlewareInterface.
This interface requires one method:
public function process(    ServerRequestInterface $request,    RequestHandlerInterface $handler): ResponseInterfaceParameters:
- $requestThe incoming HTTP request
- $handlerThe next middleware/handler in the chain
Returns:
- A response object
Step 2: Create Your Middleware Class
Section titled “Step 2: Create Your Middleware Class”Your middleware class structure should look like this:
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;use Psr\Http\Message\ServerRequestInterface;use Psr\Http\Server\MiddlewareInterface;use Psr\Http\Server\RequestHandlerInterface;
class YourMiddleware implements MiddlewareInterface{    public function process(        ServerRequestInterface $request,        RequestHandlerInterface $handler    ): ResponseInterface    {        // (optional:) Execute some code before the request is handled.
        // (required:) Pass control to the next middleware or route handler.        $response = $handler->handle($request);
        // (optional:) Execute some code after the request is handled.        // e.g.,:        //  $response = $response->withHeader('X-Custom-Header', 'value');
        return $response;    }}Step 3: Implement Your Logic
Section titled “Step 3: Implement Your Logic”Inside the process() method, you can:
Before the route handler executes:
- Inspect or modify the request
- Check conditions (authentication, validation, etc.)
- Return early if needed (e.g., unauthorized)
After the route handler executes:
- Modify the response
- Add headers
- Log information
Example flow:
public function process(    ServerRequestInterface $request,    RequestHandlerInterface $handler): ResponseInterface{    // BEFORE: Check something in the request    if ($someConditionFails) {        // Return early, don't call next middleware        $response = new Response();        return $response->withStatus(401)    }
    // Call the next middleware/handler    $response = $handler->handle($request);
    // AFTER: Modify the response    return $response->withHeader('X-Custom-Header', 'value');}Step 4: Add Dependencies (Optional)
Section titled “Step 4: Add Dependencies (Optional)”If your middleware needs services (database, session, etc.), inject them through the constructor:
class AuthMiddleware implements MiddlewareInterface{    private $sessionManager;
    public function __construct(SessionManager $sessionManager)    {        $this->sessionManager = $sessionManager;    }
    public function process(        ServerRequestInterface $request,        RequestHandlerInterface $handler    ): ResponseInterface    {        // Use $this->sessionManager here    }}Step 5: Register Your Middleware
Section titled “Step 5: Register Your Middleware”Once created, instantiate and add it to your application:
// Create instance$sessionManager = new SessionManager();$authMiddleware = new \App\Middleware\AuthMiddleware($sessionManager);
// Add to application, route, or group$app->add($authMiddleware);Key Concepts for PSR-15 Middleware
Section titled “Key Concepts for PSR-15 Middleware”1. The Handler Object
Section titled “1. The Handler Object”$handler->handle($request) passes control to the next middleware in the chain or the route handler if this is the last middleware.
Important: You must call this method unless you want to stop the chain (e.g., for authentication failure).
2. Request Immutability
Section titled “2. Request Immutability”PSR-7 requests are immutable. To modify a request:
// Wrong - doesn't work$request->setAttribute('user', $user);
// Correct - creates new request object$request = $request->withAttribute('user', $user);3. Response Immutability
Section titled “3. Response Immutability”Same applies to responses:
// Correct way to add headers$response = $response->withHeader('X-Custom', 'value');4. Early Returns
Section titled “4. Early Returns”If you need to stop the middleware chain (e.g., authentication fails), return a response without calling $handler->handle():
if (!$authenticated) {    // Stop here, don't proceed to next middleware    return $response->withStatus(401);}Checklist for Creating PSR-15 Middleware
Section titled “Checklist for Creating PSR-15 Middleware”Before you finish, verify:
-  Class implements MiddlewareInterface
-  Has process()method with correct signature
-  Calls $handler->handle($request)(unless stopping early)
-  Returns a ResponseInterfaceobject
-  Uses immutable request/response methods (withHeader,withAttribute, etc.)
- Handles both success and failure cases
- Constructor accepts any needed dependencies
- Properly namespaced in your project
Adding Middleware: Syntax Examples
Section titled “Adding Middleware: Syntax Examples”Application-Level Middleware
Section titled “Application-Level Middleware”- Applies to every single route in your application.
$middlewareInstance = new \App\Middleware\YourMiddleware();$app->add($middlewareInstance);// Or:$app->add(YourMiddleware::class);Order matters: Add from outermost to innermost layer.
Route-Level Middleware
Section titled “Route-Level Middleware”- Applies to one specific route only.
$app->get('/profile', function ($request, $response) {    // Route handler})->add($middlewareInstance);Multiple middleware on one route:
$app->get('/admin/dashboard', function ($request, $response) {    // Route handler})->add($authMiddleware)->add($adminMiddleware);The middleware closest to the route executes first for the request.
Group-Level Middleware
Section titled “Group-Level Middleware”- Applies to all routes within a group.
$app->group('/admin', function ($group) {    $group->get('/dashboard', function ($request, $response) {        // Dashboard route    });
    $group->get('/users', function ($request, $response) {        // Users route    });})->add($adminMiddleware);All routes under /admin will use the $adminMiddleware.
Nested groups with multiple middleware:
$app->group('/api', function ($group) {
    $group->group('/v1', function ($group) {        $group->get('/users', function ($request, $response) {            // API endpoint        });    })->add($versionMiddleware);
})->add($apiAuthMiddleware);Routes inherit middleware from parent groups.