Weave Code
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

Guzzle Cache Middleware Laravel Package

csa/guzzle-cache-middleware

PSR-7/PSR-18 middleware adding HTTP response caching to Guzzle clients. Cache GET/HEAD requests, reduce repeated network calls, and plug into common cache storage backends. Install via Composer and integrate in your Guzzle handler stack.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require csa/guzzle-cache-middleware
    

    Register the middleware in your Guzzle client stack:

    use CSA\GuzzleCacheMiddleware\CacheMiddleware;
    use GuzzleHttp\HandlerStack;
    
    $stack = HandlerStack::create();
    $stack->push(CacheMiddleware::cacheMiddleware(
        new \CSA\GuzzleCacheMiddleware\Cache\Psr6Cache(), // PSR-6 cache adapter
        ['ttl' => 3600] // Optional config
    ));
    
  2. First Use Case Cache API responses for a Laravel HTTP client:

    $client = new \GuzzleHttp\Client(['handler' => $stack]);
    $response = $client->get('https://api.example.com/data');
    // Subsequent identical requests will return cached responses.
    

Where to Look First


Implementation Patterns

Core Workflow

  1. Middleware Integration Inject the middleware into Guzzle’s HandlerStack for all requests:

    $stack->push(CacheMiddleware::cacheMiddleware($cacheAdapter, [
        'ttl' => 3600,
        'cache_key' => fn($request) => $request->getUri()->__toString(), // Custom key generator
    ]));
    
  2. Cache Adapter Flexibility Use any PSR-6 compatible cache (e.g., League\Flysystem\Cache\FileCache, Doctrine\Cache\Psr6Cache):

    $cache = new \Doctrine\Cache\Psr6Cache(new \Doctrine\Common\Cache\FilesystemCache('/path/to/cache'));
    
  3. Conditional Caching Skip caching for specific requests (e.g., POST/PUT):

    $stack->push(CacheMiddleware::cacheMiddleware($cache, [
        'skip_methods' => ['POST', 'PUT', 'PATCH'],
    ]));
    

Laravel-Specific Patterns

  1. Service Provider Binding Bind the middleware and cache adapter in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(\CSA\GuzzleCacheMiddleware\Cache\Psr6Cache::class, function ($app) {
            return new \Doctrine\Cache\Psr6Cache(
                new \Doctrine\Common\Cache\FilesystemCache(storage_path('framework/cache/guzzle'))
            );
        });
    }
    
  2. HTTP Client Integration Attach the middleware to Laravel’s HTTP client:

    $client = app(\Illuminate\Http\Client\PendingRequest::class)
        ->withOptions(['handler' => $stack]);
    
  3. Cache Invalidation Clear cache for specific keys (e.g., after data updates):

    $cache->delete('https://api.example.com/data');
    

Advanced Patterns

  1. Dynamic TTL Set TTL per request:

    $response = $client->get('https://api.example.com/data', [
        'cache_ttl' => 86400, // Override TTL for this request
    ]);
    
  2. Cache Key Customization Use request metadata (e.g., headers) in cache keys:

    'cache_key' => fn($request) => $request->getUri()->__toString() . '|' . $request->getHeaderLine('Authorization'),
    
  3. Cache Stampede Protection Use a lock (e.g., GuzzleHttp\Ring\Future\Lock) to prevent race conditions during cache misses.


Gotchas and Tips

Common Pitfalls

  1. Cache Key Collisions

    • Issue: Identical requests with different headers (e.g., Authorization) may collide.
    • Fix: Include headers in the cache key (see Dynamic TTL pattern above).
  2. TTL Misconfiguration

    • Issue: Setting ttl too high may serve stale data.
    • Fix: Use shorter TTLs (e.g., 300s) for volatile data and implement cache invalidation logic.
  3. Non-Idempotent Requests

    • Issue: Caching POST/PUT requests may corrupt data.
    • Fix: Exclude non-idempotent methods:
      'skip_methods' => ['POST', 'PUT', 'PATCH', 'DELETE'],
      
  4. Memory Leaks

    • Issue: Large responses (e.g., binary data) may bloat cache storage.
    • Fix: Use a disk-based cache (e.g., FileCache) or compress responses before caching.
  5. Race Conditions

    • Issue: Concurrent requests may overwrite cache during regeneration.
    • Fix: Implement a lock mechanism or use stampede_retry_after (if supported by the cache adapter).

Debugging Tips

  1. Log Cache Hits/Misses Enable debug logging for the cache adapter:

    $cache = new \Doctrine\Cache\Psr6Cache(
        new \Doctrine\Common\Cache\FilesystemCache(storage_path('logs/guzzle_cache')),
        ['logger' => \Psr\Log\LoggerInterface::class] // Inject a PSR-3 logger
    );
    
  2. Inspect Cache Keys Temporarily log generated cache keys:

    'cache_key' => function ($request) {
        $key = $request->getUri()->__toString();
        \Log::debug('Cache key:', ['key' => $key]);
        return $key;
    },
    
  3. Validate Cache Storage Manually check cache files/directory permissions:

    chmod -R 775 storage/framework/cache/guzzle
    

Extension Points

  1. Custom Cache Adapter Implement \CSA\GuzzleCacheMiddleware\Cache\CacheInterface for non-PSR-6 caches:

    class RedisCache implements CacheInterface {
        public function get($key) { /* ... */ }
        public function set($key, $value, $ttl) { /* ... */ }
        public function delete($key) { /* ... */ }
    }
    
  2. Pre/Post-Processing Modify requests/responses before caching:

    $stack->push(CacheMiddleware::cacheMiddleware($cache, [
        'pre_process' => function ($request) {
            $request = $request->withHeader('X-Cache-Enabled', 'true');
            return $request;
        },
        'post_process' => function ($response, $request) {
            return $response->withAddedHeader('X-Cache', 'HIT');
        },
    ]));
    
  3. Cache Warmup Pre-load cache for critical endpoints during deployment:

    $client->get('https://api.example.com/important-data'); // Trigger cache population
    

Configuration Quirks

  1. Default TTL

    • If ttl is omitted, the middleware uses a default of 300 seconds (5 minutes).
  2. Cache Key Normalization

    • The middleware normalizes cache keys by converting them to lowercase and trimming whitespace.
  3. Response Caching

    • Only successful responses (2xx/3xx) are cached by default. Configure cache_status_codes to override:
      'cache_status_codes' => [200, 201, 301, 302],
      
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity