HTTP Cache Middleware
http-cache-middleware is a high-performance connect-like HTTP cache middleware designed for Node.js applications. It leverages the popular `cache-manager` package, providing flexibility to integrate various storage engines like in-memory, Redis, and more. The library significantly reduces latency by enabling robust caching strategies, capable of improving response times from tens of milliseconds down to single digits. It supports custom `x-cache-timeout` and `x-cache-expire` headers for fine-grained control over cache entry and invalidation using glob patterns. Additionally, it transparently handles standard HTTP `Cache-Control` and `ETag` headers to facilitate browser-side caching and validation. The current stable version is 1.4.1, with recent updates indicating an active maintenance and development cadence focused on fixes and dependency updates, with minor cumulative releases.
Common errors
-
Redis store error when passing empty keys array to cache.del
cause Older versions of the middleware (prior to v1.3.10) would throw an error if an `x-cache-expire` pattern resulted in an empty array of keys to be deleted from the Redis cache.fixUpgrade `http-cache-middleware` to version 1.3.10 or newer. This version includes a fix that gracefully handles empty key arrays. -
Wildcard patterns in x-cache-expire are not invalidating expected entries
cause Versions prior to 1.3.8 had a bug where wildcard pattern support for cache invalidation was not working correctly.fixUpdate `http-cache-middleware` to version 1.3.8 or newer. Ensure your patterns are valid according to the `matcher` package syntax (e.g., `*/users` to match all paths ending with `/users`). -
TypeError: middleware is not a function
cause In CommonJS environments, the `require('http-cache-middleware')` call returns a factory function, which must then be invoked to get the actual middleware instance. Developers often forget to call this function.fixEnsure you invoke the factory function: `const middleware = require('http-cache-middleware')();`
Warnings
- gotcha The `ms` package, used for parsing `x-cache-timeout` header values, does not support the 'millisecond' unit. Ensure you use supported units like 'second', 'minute', 'hour', etc.
- gotcha When using `x-cache-timeout` to automatically generate `Cache-Control` and `ETag` headers for browser caching, these generated headers will only be observable on subsequent requests *after* the initial response has been cached (i.e., on a cache hit).
- breaking Fixes were introduced in v1.3.8 for wildcard pattern support in `x-cache-expire` that were previously not working as described. If you relied on broken behavior or custom workarounds, this fix might change behavior.
- breaking Version 1.3.5 introduced ordered, two-step async cache writing to prevent timing issues under high concurrency. While a fix, systems relying on specific concurrent cache writing behaviors might observe changes.
- breaking A critical bug in v1.3.10 fixed `redis store error when passing empty keys array` to `cache.del`. Older versions would throw an error if an empty array was passed for cache invalidation.
- breaking The integration of `iff` and `unless` utility functions was fixed in v1.4.1. Previous versions might have had inconsistent or incorrect conditional middleware execution.
Install
-
npm install http-cache-middleware -
yarn add http-cache-middleware -
pnpm add http-cache-middleware
Imports
- middleware
import { middleware } from 'http-cache-middleware'import createCacheMiddleware from 'http-cache-middleware'; const middleware = createCacheMiddleware();
- CacheManager
import CacheManager from 'cache-manager'
import { caching } from 'cache-manager'; const redisCache = caching({ store: redisStore, ... }); - httpCacheMiddleware
const httpCacheMiddleware = require('http-cache-middleware')const httpCacheMiddleware = require('http-cache-middleware')();
Quickstart
import createCacheMiddleware from 'http-cache-middleware';
import restana from 'restana';
const middleware = createCacheMiddleware();
const service = restana();
service.use(middleware);
service.get('/cache-on-get', (req, res) => {
setTimeout(() => {
res.setHeader('x-cache-timeout', '1 minute');
res.send('this supposed to be a cacheable response, fetched at ' + new Date().toISOString());
}, 50);
});
service.delete('/invalidate-cache', (req, res) => {
// Simulate a data change that requires cache invalidation
console.log('Invalidating cache for /cache-on-get');
res.setHeader('x-cache-expire', '*/cache-on-get');
res.send('Cache invalidated');
});
const port = process.env.PORT || 3000;
service.start(port).then(() => {
console.log(`Server started on port ${port}`);
console.log(`Try: curl http://localhost:${port}/cache-on-get`);
console.log(`Then: curl http://localhost:${port}/invalidate-cache`);
console.log(`Then: curl http://localhost:${port}/cache-on-get again`);
});