Implement comprehensive multi-level API caching strategies with Redis, CDN,...
Creates comprehensive multi-level caching strategies with Redis and CDN integration to improve API performance.
/plugin marketplace add jeremylongshore/claude-code-plugins-plus/plugin install api-cache-manager@claude-code-plugins-plusCreates comprehensive multi-level caching strategies to dramatically improve API performance, reduce database load, and enhance user experience. Implements Redis for server-side caching, CDN integration for edge caching, and proper HTTP cache headers for client-side optimization.
Use this command when:
Do NOT use this command for:
Before running this command, ensure:
The command examines your API to determine optimal caching strategies:
Sets up Redis-based caching with intelligent patterns:
Implements proper HTTP caching directives:
Configures edge caching for global distribution:
Creates sophisticated invalidation strategies:
The command generates a complete caching implementation:
api-caching/
├── src/
│ ├── cache/
│ │ ├── redis-client.js
│ │ ├── cache-middleware.js
│ │ ├── cache-strategies.js
│ │ └── invalidation-service.js
│ ├── middleware/
│ │ ├── http-cache-headers.js
│ │ └── cdn-integration.js
│ └── utils/
│ ├── cache-key-generator.js
│ └── cache-metrics.js
├── config/
│ ├── cache-config.json
│ ├── redis.config.js
│ └── cdn-rules.json
├── tests/
│ └── cache.test.js
└── docs/
└── caching-strategy.md
Scenario: High-traffic product catalog requiring sub-100ms response times
Generated Redis Implementation:
// cache/redis-client.js
import Redis from 'ioredis';
import { promisify } from 'util';
class CacheManager {
constructor() {
this.client = new Redis({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD,
retryStrategy: (times) => Math.min(times * 50, 2000),
enableOfflineQueue: false
});
this.defaultTTL = 3600; // 1 hour default
this.client.on('error', this.handleError);
}
async get(key, options = {}) {
try {
const cached = await this.client.get(key);
if (cached) {
this.metrics.hit(key);
return JSON.parse(cached);
}
this.metrics.miss(key);
// Cache-aside pattern: fetch if not cached
if (options.fetchFunction) {
const data = await options.fetchFunction();
await this.set(key, data, options.ttl);
return data;
}
return null;
} catch (error) {
this.handleError(error);
// Fallback to direct fetch on cache error
return options.fetchFunction ? await options.fetchFunction() : null;
}
}
async set(key, value, ttl = this.defaultTTL) {
const serialized = JSON.stringify(value);
if (ttl) {
await this.client.setex(key, ttl, serialized);
} else {
await this.client.set(key, serialized);
}
// Implement cache tags for invalidation
if (value.tags) {
for (const tag of value.tags) {
await this.client.sadd(`tag:${tag}`, key);
}
}
}
async invalidateByTag(tag) {
const keys = await this.client.smembers(`tag:${tag}`);
if (keys.length > 0) {
await this.client.del(...keys);
await this.client.del(`tag:${tag}`);
}
return keys.length;
}
async invalidatePattern(pattern) {
const keys = await this.client.keys(pattern);
if (keys.length > 0) {
await this.client.del(...keys);
}
return keys.length;
}
}
// middleware/cache-middleware.js
export const cacheMiddleware = (options = {}) => {
return async (req, res, next) => {
// Skip caching for non-GET requests
if (req.method !== 'GET') {
return next();
}
// Generate cache key
const cacheKey = generateCacheKey(req);
// Check cache
const cached = await cacheManager.get(cacheKey);
if (cached) {
res.set('X-Cache', 'HIT');
res.set('X-Cache-Key', cacheKey);
return res.json(cached);
}
// Store original send function
const originalSend = res.json;
res.json = function(data) {
res.json = originalSend;
// Cache successful responses only
if (res.statusCode === 200) {
cacheManager.set(cacheKey, data, options.ttl);
}
res.set('X-Cache', 'MISS');
res.set('X-Cache-Key', cacheKey);
return res.json(data);
};
next();
};
};
// Usage in Express routes
app.get('/api/products/:id',
cacheMiddleware({ ttl: 1800 }), // 30 minutes
async (req, res) => {
const product = await db.getProduct(req.params.id);
res.json(product);
}
);
Scenario: Global content delivery with CloudFlare integration
Generated CDN Configuration:
// cdn-integration.js
class CDNManager {
constructor(config) {
this.zoneId = config.cloudflareZoneId;
this.apiToken = config.cloudflareApiToken;
this.baseUrl = 'https://api.cloudflare.com/client/v4';
}
// Set CDN cache headers
setCacheHeaders(res, options = {}) {
const {
maxAge = 3600,
sMaxAge = 86400,
staleWhileRevalidate = 60,
staleIfError = 3600,
mustRevalidate = false,
public = true
} = options;
// Browser cache
let cacheControl = public ? 'public' : 'private';
cacheControl += `, max-age=${maxAge}`;
// CDN cache (s-maxage)
cacheControl += `, s-maxage=${sMaxAge}`;
// Stale content serving
if (staleWhileRevalidate) {
cacheControl += `, stale-while-revalidate=${staleWhileRevalidate}`;
}
if (staleIfError) {
cacheControl += `, stale-if-error=${staleIfError}`;
}
if (mustRevalidate) {
cacheControl += ', must-revalidate';
}
res.set('Cache-Control', cacheControl);
// CloudFlare specific headers
res.set('CF-Cache-Tag', options.tags?.join(',') || 'default');
// Enable CDN caching for this response
res.set('CDN-Cache-Control', `max-age=${sMaxAge}`);
}
// Purge CDN cache by URL or tag
async purgeCache(options = {}) {
const { urls, tags, everything = false } = options;
let purgeBody = {};
if (everything) {
purgeBody.purge_everything = true;
} else if (tags) {
purgeBody.tags = tags;
} else if (urls) {
purgeBody.files = urls;
}
const response = await fetch(
`${this.baseUrl}/zones/${this.zoneId}/purge_cache`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(purgeBody)
}
);
return response.json();
}
}
// Usage in API endpoints
app.get('/api/content/:slug', async (req, res) => {
const content = await cms.getContent(req.params.slug);
// Set aggressive CDN caching for static content
cdnManager.setCacheHeaders(res, {
maxAge: 300, // 5 min browser cache
sMaxAge: 86400, // 24 hour CDN cache
tags: ['content', `content-${content.id}`]
});
res.json(content);
});
// Invalidate on content update
app.post('/api/content/:slug/update', async (req, res) => {
const content = await cms.updateContent(req.params.slug, req.body);
// Purge CDN cache
await cdnManager.purgeCache({
tags: [`content-${content.id}`]
});
// Invalidate Redis cache
await cacheManager.invalidateByTag(`content-${content.id}`);
res.json({ success: true });
});
Scenario: Critical data that must always be cached for performance
Generated Cache Warming Strategy:
// cache-warming-service.js
class CacheWarmer {
constructor(cacheManager, dataSource) {
this.cache = cacheManager;
this.dataSource = dataSource;
this.warmingInterval = 5 * 60 * 1000; // 5 minutes
}
async warmCache() {
console.log('Starting cache warming...');
// Warm frequently accessed data
const criticalData = [
{ key: 'homepage:featured', fetch: () => this.dataSource.getFeaturedProducts() },
{ key: 'categories:all', fetch: () => this.dataSource.getAllCategories() },
{ key: 'config:site', fetch: () => this.dataSource.getSiteConfig() }
];
const warmingPromises = criticalData.map(async ({ key, fetch }) => {
try {
const data = await fetch();
await this.cache.set(key, data, 3600); // 1 hour TTL
return { key, status: 'warmed' };
} catch (error) {
return { key, status: 'failed', error: error.message };
}
});
const results = await Promise.allSettled(warmingPromises);
console.log('Cache warming complete:', results);
return results;
}
startPeriodicWarming() {
// Initial warming
this.warmCache();
// Periodic warming
setInterval(() => {
this.warmCache();
}, this.warmingInterval);
}
}
Symptoms: Cache operations timeout or fail Cause: Redis server unavailable or misconfigured Solution:
// Implement fallback to direct database access
if (!redis.isReady()) {
console.warn('Cache unavailable, falling back to database');
return await database.query(sql);
}
Prevention: Implement circuit breaker pattern and health checks
Symptoms: Multiple simultaneous cache misses cause database overload Cause: Popular item expires, causing many requests to rebuild cache Solution: Implement probabilistic early expiration or distributed locks
Symptoms: Users see outdated information Cause: Cache TTL too long or invalidation not triggered Solution: Implement event-based invalidation and reduce TTL values
--ttl/cache --ttl 7200--strategycache-aside, write-through, write-behindcache-aside/cache --strategy write-through--cdncloudflare, fastly, cloudfront, akamaicloudflare/cache --cdn fastly✅ DO:
❌ DON'T:
💡 TIPS:
/api-rate-limiter - Implement rate limiting with Redis/api-response-validator - Validate cached responses/api-monitoring-dashboard - Monitor cache performance/api-load-tester - Test cache effectiveness under load⚠️ Security Considerations:
Solution: Review cache key strategy and TTL values
Solution: Implement LRU eviction policy and reduce object sizes
Solution: Verify tag associations and event triggers
Last updated: 2025-10-11 Quality score: 9.5/10 Tested with: Redis 7.0, CloudFlare, Fastly, AWS CloudFront