Response cache middleware
Esta página aún no está disponible en tu idioma.
cached wraps a handler with response caching keyed by a
user-supplied key(req) function. A cache hit serves the
stored response without invoking the underlying handler.
import { cached, path, get } from 'actor-ts/http';import { InMemoryCache } from 'actor-ts';
const productCache = cached({ cache: new InMemoryCache(), ttlMs: 30_000, key: (req) => `products:${pathParam(req, 'id')}`,});
const routes = path('api', path('products', get(productCache(async (req) => /* expensive lookup */)), ),);Cache for 30 seconds per product ID. First request hits the handler; subsequent GETs in the next 30 s return the cached response.
Configuration
Section titled “Configuration”interface ResponseCacheOptions { cache: Cache; ttlMs: number; key: (req: HttpRequest) => string | Promise<string>; keyPrefix?: string; // default 'rsp:' cacheStatuses?: ReadonlyArray<number>; // default [200]}| Field | Purpose |
|---|---|
cache | The Cache backend. InMemoryCache for single-node; Redis for shared. |
ttlMs | How long each cached response stays valid. |
key(req) | Derive the cache key from the request — typically includes URL params, tenant ID, accept header etc. Required. |
keyPrefix | Cache-key namespace. Default 'rsp:' so multiple response-caches in the same Redis don’t collide. |
cacheStatuses | Which status codes are cacheable. Default [200] — only 2xx responses get cached. |
Cache key composition
Section titled “Cache key composition”The key(req) function is the entire cache-key contract — what
you include there determines what’s cached separately. Common
patterns:
// Per-URL-path key:key: (req) => req.url.pathname,
// Per-tenant:key: (req) => `${req.headers['x-tenant-id'] ?? 'public'}:${req.url.pathname}`,
// Per-locale + content type:key: (req) => `${req.headers['accept-language']}:${req.headers['accept']}:${req.url.pathname}`,Build the key to be deterministic across equivalent requests but unique across responses you want cached separately.
When to cache
Section titled “When to cache”GET /api/products → cache (stable, read-heavy)POST /api/orders → don't wrap with cached() (mutation)GET /api/users/me → cache only with per-user keyGET /api/feed?cursor=X → cache (one entry per cursor)The wrapper is a handler-level decision — you choose which
handlers to wrap. Mutations should typically use
idempotent instead.
Cache invalidation
Section titled “Cache invalidation”cached doesn’t auto-invalidate on writes — staleness is
bounded by ttlMs.
For stronger consistency, two patterns:
Short TTLs
Section titled “Short TTLs”cached({ cache, ttlMs: 1_000, key }); // 1 secondSub-second TTLs limit staleness. Good for “real-time-ish” APIs.
Manual invalidation
Section titled “Manual invalidation”// After a write that affects products:42, invalidate the cache:await cache.delete('rsp:products:42'); // 'rsp:' is the default keyPrefixThe cache is just a Cache — you can delete the prefixed key
directly when a write should invalidate it.
Shared cache across pods
Section titled “Shared cache across pods”import { RedisCache } from 'actor-ts';
const productCache = cached({ cache: new RedisCache({ url: 'redis://...' }), ttlMs: 30_000, key: (req) => `products:${pathParam(req, 'id')}`,});With a Redis-backed cache, all pods share the same cache — useful for multi-pod deployments where you want consistent caching.
For per-pod caches (each pod has its own InMemoryCache), pods may serve different cached responses briefly until TTLs align. Often acceptable; depends on consistency requirements.
Caching different status codes
Section titled “Caching different status codes”cached({ cache, ttlMs: 30_000, key, cacheStatuses: [200, 404], // cache both hits AND "not found"s});Cache 404s when you’ve got many lookups for IDs that don’t
exist — saves repeat DB hits. Defaults to [200] only so a
transient 500 never sticks around for 30 seconds.
Where to next
Section titled “Where to next”- HTTP overview — the bigger picture.
- Rate limit middleware — complementary middleware.
- Idempotency-key middleware — for write-dedup.
- Cache overview — the backend this middleware uses.