Api Caching Project
DodaTech
2 min read
title: "API Caching Project — Build a Multi-Tier Caching System" description: "Build a production multi-tier caching system with Redis, Nginx reverse proxy, HTTP headers, and CDN configuration for a real API deployment." date: 2026-06-28 lastmod: 2026-06-28 weight: 25 tags: [apis, caching] }
Build a complete multi-tier caching system for an API combining Redis application caching, Nginx reverse proxy, HTTP cache headers, and CDN configuration.
What You'll Learn
- Implementing a multi-tier cache
- TTL coordination and cache invalidation
- Measuring cache performance
Why It Matters
This project combines all caching concepts into a deployable caching layer that improves API response time from 200ms to under 10ms.
Project Structure
# app.py - Complete caching API
from flask import Flask, request, jsonify
import redis, hashlib, json, threading, time
from functools import wraps
app = Flask(__name__)
redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)
# Cache decorator with multi-tier support
def cache(ttl=300, stale_ttl=600):
def decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
key = f'api:{request.path}:{hashlib.md5(request.query_string).hexdigest()}'
# Try Redis
cached = redis_client.get(key)
if cached:
response = jsonify(json.loads(cached))
response.headers['X-Cache-Tier'] = 'redis'
response.headers['Cache-Control'] = f'public, max-age={min(60, ttl)}'
return response
# Compute response
data = f(*args, **kwargs)
redis_client.setex(key, ttl, json.dumps(data))
response = jsonify(data)
response.headers['X-Cache-Tier'] = 'miss'
response.headers['Cache-Control'] = f'public, max-age={min(60, ttl)}'
response.headers['ETag'] = hashlib.sha256(
json.dumps(data, sort_keys=True).encode()
).hexdigest()
return response
return wrapper
return decorator
@app.route('/api/products')
@cache(ttl=300)
def get_products():
# Simulate DB query
time.sleep(0.1)
return [{"id": i, "name": f"Product {i}"} for i in range(100)]
# nginx.conf - Reverse proxy cache layer
http {
upstream app {
server localhost:5000;
}
proxy_cache_path /var/cache/nginx levels=1:2
keys_zone=api_cache:10m
max_size=1g
inactive=60m;
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_cache api_cache;
proxy_cache_valid 200 5m;
proxy_cache_key "$host$request_uri";
proxy_pass http://app;
add_header X-Cache-Status $upstream_cache_status;
add_header X-Cache-Tier "nginx" always;
# Bypass cache for POST/PUT/DELETE
proxy_no_cache $request_method;
proxy_cache_bypass $request_method;
}
}
}
Testing and Monitoring
# test_caching.py
def test_cache_performance():
import requests
import time
base = 'http://localhost:5000'
# First request (cold)
start = time.time()
r1 = requests.get(f'{base}/api/products')
cold_time = time.time() - start
print(f'Cold request: {cold_time*1000:.1f}ms')
# Second request (cached)
start = time.time()
r2 = requests.get(f'{base}/api/products')
hot_time = time.time() - start
print(f'Cached request: {hot_time*1000:.1f}ms')
# Verify cache headers
assert 'X-Cache-Tier' in r2.headers
print(f'Improvement: {cold_time/hot_time:.0f}x faster')
Challenge
Extend the project with:
- Cache purging endpoint that invalidates by key pattern
- Prometheus metrics for cache hit ratio
- Stale-while-revalidate pattern
- Distributed cache locking for stampede prevention
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro