Skip to content
lpachecob edited this page Mar 24, 2026 · 1 revision

πŸš€ Response Cache

BOUNDLY v0.9.0 includes automatic API response caching for improved performance.


πŸ“ Location

Infrastructure\FrameworkCore\Http\Middleware\ResponseCacheMiddleware.php

⚑ Quick Start

Enable caching in configuration:

// config/boundly.php
'cache' => [
    'response' => [
        'enabled' => true,
        'store' => 'file',  // or 'redis', 'memcached'
        'ttl' => 60,        // Cache TTL in minutes
        'exclude_paths' => ['api/health', 'api/*/health'],
    ],
],

πŸ”§ How It Works

  1. First Request (MISS): Response is cached and returned
  2. Subsequent Requests (HIT): Cached response is returned immediately
  3. Cache Key: Based on path + query parameters + Accept-Language

Response Headers

X-Cache: HIT
X-Cache: MISS

🎯 Using in Actions

Automatic via Middleware

#[Action(resource: 'products', method: 'GET', middleware: ['cache.response:30'])]
class ListProductsAction
{
    public function execute(): JsonResponse
    {
        // Response will be cached for 30 minutes
        return response()->json(Product::all());
    }
}

Manual Cache Control

use Illuminate\Support\Facades\Cache;

class ProductController
{
    public function show($id)
    {
        $product = Cache::remember("product:{$id}", 60, function () use ($id) {
            return Product::findOrFail($id);
        });

        return response()->json($product);
    }

    public function update(Request $request, $id)
    {
        $product = Product::findOrFail($id);
        $product->update($request->validated());

        // Invalidate cache
        Cache::forget("product:{$id}");

        return response()->json($product);
    }
}

πŸ—‘οΈ Cache Invalidation

Automatic Invalidation

BOUNDLY can automatically invalidate cache when entities are modified:

// config/boundly.php
'cache' => [
    'response' => [
        'enabled' => true,
        'auto_invalidate' => true,
        'invalidate_on' => ['created', 'updated', 'deleted'],
    ],
],

Manual Invalidation

use Infrastructure\FrameworkCore\Http\Middleware\ResponseCacheMiddleware;

$middleware = app(ResponseCacheMiddleware::class);

// Invalidate specific path
$middleware->invalidate('api/products', ['page' => 1]);

// Invalidate all cached responses
$middleware->invalidateAll();

Cache Tags (Redis)

// Tag-based invalidation with Redis
Cache::tags(['products', 'category_5'])->flush();

βš™οΈ Configuration Options

// config/boundly.php
'cache' => [
    'response' => [
        'enabled' => true,
        'store' => env('CACHE_DRIVER', 'file'),
        'ttl' => 60,  // Default TTL in minutes
        'exclude_paths' => [
            'api/health',
            'api/*/health',
            'api/auth/*',
            'api/admin/*',
        ],
        'vary_by' => [
            'accept_language',
            'accept_encoding',
        ],
    ],
],
Option Default Description
enabled false Enable/disable response caching
store 'file' Cache store driver
ttl 60 Default TTL in minutes
exclude_paths [] Paths to never cache
vary_by [] Headers that affect cache key

πŸ” Security Considerations

Never Cache Sensitive Data

Excluded paths are automatically bypassed:

'exclude_paths' => [
    'api/health',           // Health checks
    'api/auth/*',           // Authentication endpoints
    'api/users/me',         // User-specific data
    'api/*/sensitive',      // Sensitive resources
],

Cache-Control Headers

Responses from cache include appropriate headers:

Cache-Control: public, max-age=3600
X-Cache: HIT

πŸ“Š Performance Benefits

Scenario Without Cache With Cache
GET /api/products ~150ms ~5ms
GET /api/products/123 ~80ms ~2ms
GET /api/users?page=1 ~200ms ~10ms

πŸ§ͺ Testing Cached Responses

public function test_products_are_cached()
{
    $response = $this->getJson('/api/products');
    $response->assertHeader('X-Cache', 'MISS');

    // Second request should be cached
    $response = $this->getJson('/api/products');
    $response->assertHeader('X-Cache', 'HIT');
}

πŸ”§ Cache Stores

File Cache (Default)

'store' => 'file',

Simple, no external dependencies. Good for single-server deployments.

Redis

'store' => 'redis',
CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

Best for multi-server deployments with high traffic.

Memcached

'store' => 'memcached',
CACHE_DRIVER=memcached
MEMCACHED_HOST=127.0.0.1
MEMCACHED_PORT=11211

High-performance option for large-scale applications.


πŸ› Troubleshooting

Cache Not Working

  1. Verify cache.response.enabled is true
  2. Check cache store is configured correctly
  3. Ensure path is not in exclude_paths
  4. Verify cache directory is writable

Stale Data

  1. Reduce TTL for frequently updated resources
  2. Implement cache invalidation on updates
  3. Use cache tags for selective invalidation

Next Step: Exception-Handling ⚠️

Clone this wiki locally