Featured image of post Using Middleware for Request Caching in Slim4

Using Middleware for Request Caching in Slim4

Caching API Responses in the Slim Framework

When developing web pages or API interfaces, we often encounter the following scenario:

  1. A request is processed by querying the database and returning transformed data
  2. Some pages/interfaces with infrequent data changes (e.g. homepage) may experience performance issues under high traffic
  3. Solution: Cache processed content in storage like Redis before returning the response
  4. Subsequent requests first check the cache - return immediately if valid
  5. If cache expires, repeat steps [3-4]

Here’s an implementation in Slim4 framework:

<?php

namespace App\Middleware;

use Nyholm\Psr7\Stream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class PageCacheMiddleware
{
    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $cachedRoutes = [
            '/' => [],
            '/categories' => [],
            '/articles' => [],
        ];
        $requestPath = $request->getUri()->getPath();

        // Bypass non-GET requests and uncached routes
        if (
            (strtoupper($request->getMethod()) !== 'GET') ||
            !array_key_exists($requestPath, $cachedRoutes)
        ) {
            return $handler->handle($request);
        }

        // Generate cache key considering query parameters
        $requestParameters = $request->getQueryParams();
        $cacheKey = base64_encode($requestPath . json_encode($requestParameters));

        // Simulating cache storage with file system (replace with Redis in production)
        if (file_exists($cacheKey)) {
            list($cachedResponse, $cachedBody) = unserialize(file_get_contents($cacheKey));
            if ($cachedResponse instanceof ResponseInterface) {
                return $cachedResponse->withBody(Stream::create($cachedBody));
            }
        }

        // Process request and cache response
        $response = $handler->handle($request);
        file_put_contents(
            $cacheKey,
            serialize([$response, (string)$response->getBody()])
        );

        return $response;
    }
}

Key implementation details:

  1. Only cache specified GET routes
  2. Cache key includes URL path and query parameters
  3. Serializes both response object and body content
  4. File-based caching for demonstration (replace with Redis/Memcached in production)

This middleware checks the cache before processing requests and stores responses after initial processing, effectively reducing database queries and computational overhead for cached endpoints.