# new CacheService()
Cache service with adapter pattern for flexible backend support.
CacheService provides a unified caching API that works with multiple backends (InMemory, Redis, Datadog) via adapter pattern. It's used at two levels:
- HTTP Layer: Via cacheHandler() middleware for route-level caching
- Service Layer: Via withCacheable() mixin for method-level caching with entity rehydration
Adapter Requirements: All adapters must implement this interface:
interface CacheAdapter {
get(key: string): Promise<any>;
set(key: string, value: any, ttl?: number): Promise<void>;
del(keys: string | string[]): Promise<void>;
keys(): Promise<string[]>;
}
Cache Key Generation: Keys are deterministic - same parameters always generate same key regardless of order:
cache.getCacheKey('icons', { page: 1, limit: 10 });
cache.getCacheKey('icons', { limit: 10, page: 1 });
// Both produce: 'icons:a1b2c3d4e5f6...'
Performance Characteristics:
- InMemory: ~0.01ms per operation (development/testing)
- Redis: ~1-5ms per operation (production, network overhead)
- Datadog: ~10-50ms per operation (observability, write-heavy)
Examples
// Development setup with InMemory adapter
const NodeCache = require('node-cache');
const cache = new CacheService(new NodeCacheAdapter(new NodeCache()));
// Production setup with Redis adapter
const redis = require('redis');
const client = await redis.createClient({
url: process.env.REDIS_URL,
socket: { reconnectStrategy: (retries) => Math.min(retries * 50, 500) }
}).connect();
const cache = new CacheService(new RedisAdapter(client));
// HTTP route caching
app.get('/api/icons/:id',
cache.cacheHandler('icons:detail', async (req) => {
return iconService.getById(req.params.id);
}, 3600)
);
// Service-level caching (automatic with withCacheable mixin)
class IconService extends withCacheable(BaseService) {
// All methods like getById() are automatically cached
}
Methods
# cacheHandler(baseKey, handler, ttlopt) → {function}
Express/Fastify middleware for automatic request caching.
Supports cache modes via query parameter ?cacheMode=skip|bust|refresh:
- DEFAULT: Return cached data if available, otherwise fetch and cache
- SKIP: Bypass cache, always fetch fresh data
- BUST: Clear cache entry, fetch fresh data, don't re-cache
- REFRESH: Clear cache entry, fetch fresh data, cache the result
The middleware automatically:
- Generates cache keys from request parameters
- Includes user ID in cache key if authenticated
- Adds
fromCache: true/falseto response - Handles errors with next()
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
baseKey |
string
|
Base cache key for this route |
||
handler |
function
|
Async function that returns data: |
||
ttl |
number
|
<optional> |
kCACHE_DEFAULT_TTL | Time-to-live in seconds |
Express/Fastify middleware function
function
Examples
// Basic usage
app.get('/api/icons',
cache.cacheHandler('icons:list', async (req) => {
return iconService.getAll(req.query);
}, 3600)
);
// Client can control cache behavior:
// GET /api/icons?cacheMode=skip - Always fresh
// GET /api/icons?cacheMode=bust - Clear and fetch
// GET /api/icons?cacheMode=refresh - Update cache
// With authentication
app.get('/api/favorites',
authenticate,
cache.cacheHandler('favorites', async (req) => {
return favoriteService.getUserFavorites(req.user.id);
})
);
// Cache key includes user.id automatically
# async clearCache(optionsopt) → {Promise.<number>}
Clears cache entries by base key prefix or custom matcher function.
Useful for cache invalidation when data changes:
- Clear all keys with a specific prefix
- Clear keys matching custom criteria
- Clear all keys (no parameters)
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
options |
Object
|
<optional> |
{} | Clearing options |
baseKey |
string
|
<optional> |
Clear all keys starting with this prefix |
|
matcher |
function
|
<optional> |
Custom function to filter keys: |
Number of keys cleared
Promise.<number>
Examples
// Clear all icon-related cache entries
await cache.clearCache({ baseKey: 'icons' });
// Clears: icons:list, icons:detail:*, etc.
// Clear with custom matcher
await cache.clearCache({
matcher: (key) => key.includes('user:123')
});
// Clear all cache entries
await cache.clearCache();
// Clear after data update
await iconService.updateIcon(id, data);
await cache.clearCache({ baseKey: 'icons' });
# getCacheKey(baseKey, paramsopt, userIdopt) → {string}
Generates a consistent cache key from base key, parameters, and user ID.
Keys are generated by:
- Sorting parameter keys alphabetically
- Serializing values (objects sorted by keys)
- Appending user ID if provided
- Hashing the combined string with MD5
This ensures the same parameters always generate the same key, regardless of parameter order.
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
baseKey |
string
|
The base cache key (e.g., 'users:list', 'products:detail') |
||
params |
Object
|
<optional> |
{} | Query parameters or options |
userId |
number
|
string
|
<optional> |
null | User ID for user-specific caching |
Hashed cache key in format 'baseKey:hash'
string
Examples
const key1 = cache.getCacheKey('icons', { page: 1, limit: 10 });
const key2 = cache.getCacheKey('icons', { limit: 10, page: 1 });
// key1 === key2 (order doesn't matter)
// User-specific caching
const key = cache.getCacheKey('favorites', { page: 1 }, userId);
// Returns: 'favorites:abc123def456...'
// With object parameters
const key = cache.getCacheKey('search', {
filters: { category: 'icons', style: 'outline' },
sort: 'name'
});