cache function
In-memory response cache middleware.
Caches full responses keyed by URL (or a custom keyGenerator). On a cache
hit the response is returned immediately without running the handler.
Cached entries are automatically invalidated when max-age in
cacheControl expires.
Responses with Cache-Control: no-store/no-cache/private, Vary: *, or
Set-Cookie headers are never cached.
// Basic — cache all 200 responses for 1 hour
app.get('*', cache(
cacheName: 'my-app',
cacheControl: 'max-age=3600',
));
// Cache specific status codes
app.get('*', cache(
cacheName: 'my-app',
cacheControl: 'max-age=3600',
cacheableStatusCodes: [200, 404, 412],
));
// Custom key + lifecycle hooks
app.use(cache(
cacheName: 'my-app-v1',
keyGenerator: (c) => '${c.req.method}:${c.req.path}',
onCacheNotAvailable: () =>
print('Custom log: Cache API is not available.'),
));
Implementation
Middleware cache({
required String cacheName,
bool wait = false, // kept for API compatibility
String? cacheControl,
FutureOr<String> Function(Context c)? keyGenerator,
List<int> cacheableStatusCodes = const [200],
void Function()? onCacheNotAvailable,
}) {
final store = _openStore(cacheName);
final maxAge = _parseMaxAge(cacheControl);
return (Context c, Next next) async {
final key = keyGenerator != null
? await keyGenerator(c)
: c.req.url.toString();
// ── Cache hit ──────────────────────────────────────────────────────────
final entry = store[key];
if (entry != null && !entry.isExpired) {
c.respond(entry.response);
if (cacheControl != null) c.header('Cache-Control', cacheControl);
return;
}
// Remove stale entry so it doesn't block future caching
if (entry != null && entry.isExpired) store.remove(key);
// ── Cache miss ─────────────────────────────────────────────────────────
await next();
final response = c.response;
if (response == null) return;
if (!cacheableStatusCodes.contains(response.statusCode)) return;
if (_shouldSkipCache(response)) return;
if (cacheControl != null) c.header('Cache-Control', cacheControl);
final expiresAt = maxAge != null
? DateTime.now().add(Duration(seconds: maxAge))
: null;
store[key] = _CachedEntry(response, expiresAt);
};
}