Cache middlewares
Initial configuration
To begin using the cache middlewares, you'll need to create and configure a CacheResolver instance:
import { CacheResolver } from "eridu-tech/cache";
import { MemoryCacheAdapter } from "eridu-tech/cache/memory-cache-adapter";
import { RedisCacheAdapter } from "eridu-tech/cache/redis-cache-adapter";
import { SuperJsonSerde } from "eridu-tech/serde/super-json-serde";
import { Redis } from "ioredis";
const serde = new SuperJsonSerde();
export const cacheResolver = new CacheResolver({
adapters: {
memory: new MemoryCacheAdapter(),
redis: new RedisCacheAdapter({
database: new Redis("YOUR_REDIS_CONNECTION_STRING"),
serde,
}),
},
defaultAdapter: "memory",
});
await cacheResolver.init();
export const cache = cacheResolver.use();
withCacheFactory middleware
The Cache middleware intercepts function calls and caches their return values using a configurable cache store. When the wrapped function is invoked, the middleware derives a cache key from the function's arguments. If the key exists in the cache, the cached value is returned immediately without executing the function. Otherwise, the function runs, its result is stored in the cache, and the result is returned.
Usage
import { withCacheFactory } from "eridu-tech/cache/middlewares";
import { use } from "eridu-tech/middleware";
import { TimeSpan } from "eridu-tech/time-span";
import { cacheResolver } from "./cache.js";
const withCache = withCacheFactory(cacheResolver);
const fetchUser = async (userId: string): Promise<{ name: string }> => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
};
// Wrap with caching using the default adapter (`memory`)
const cachedFetchUser = use(
fetchUser,
withCache({
key: ([userId]) => `user:${userId}`,
ttl: TimeSpan.fromMinutes(10), // Cache for 10 minutes
}),
);
// Wrap with caching using a specific adapter (`redis`)
const cachedFetchUserOnRedis = use(
fetchUser,
withCache.use("redis")({
key: ([userId]) => `user:${userId}`,
ttl: TimeSpan.fromMinutes(10),
}),
);
const user = await cachedFetchUser("123"); // Cache miss — fetches and caches
const userAgain = await cachedFetchUser("123"); // Cache hit — returns immediately
const userOnRedis = await cachedFetchUserOnRedis("123"); // Uses the Redis adapter
Calling withCache() directly uses the resolver's default adapter (memory). Use withCache.use("redis") to run the wrapped function through a specific registered adapter.
Here is a complete list of settings for the withCache function.
withInvalidationFactory middleware
The Cache invalidation middleware intercepts function calls and invalidates a cache entry after the wrapped function has been invoked. The cache key is derived from the function's arguments via the key setting. After the wrapped function runs, the shouldInvalidate setting decides whether to invalidate based on the function's arguments and return value; when it returns true (the default), the cache entry is removed from the selected cache adapter.
This is useful for write-invalidation caching patterns, where stale cached data must be cleared after a mutation.
Usage
import { withInvalidationFactory } from "eridu-tech/cache/middlewares";
import { use } from "eridu-tech/middleware";
import { cacheResolver } from "./cache.js";
const withInvalidation = withInvalidationFactory(cacheResolver);
const updateUser = async (userId: string, name: string): Promise<void> => {
await fetch(`/api/users/${userId}`, {
method: "PUT",
body: JSON.stringify({ name }),
});
};
// Wrap with invalidation using the default adapter (`memory`)
const invalidatingUpdateUser = use(
updateUser,
withInvalidation({
key: ([userId]) => `user:${userId}`,
}),
);
// Wrap with invalidation using a specific adapter (`redis`)
const invalidatingUpdateUserOnRedis = use(
updateUser,
withInvalidation.use("redis")({
key: ([userId]) => `user:${userId}`,
}),
);
await invalidatingUpdateUser("123", "John");
// The "user:123" cache entry is removed after updateUser runs
await invalidatingUpdateUserOnRedis("456", "Jane");
// The "user:456" cache entry is removed from the Redis adapter
Use withInvalidation() to invalidate through the resolver's default adapter (memory in this example), or withInvalidation.use("redis")({ ... }) to select a specific adapter.
Here is a complete list of settings for the withInvalidation function.
Settings
| Option | Type | Description |
|---|---|---|
key | Invocable<TParameters, string> | A function (or invocable object) that produces the cache key from the wrapped function's arguments |
shouldInvalidate | Invocable<[args: TParameters, returnValue: TReturn], boolean> | Determines whether to invalidate the cache entry after the wrapped function runs, based on its arguments and return value. Defaults to () => true |
Further information
For further information refer to eridu-tech/cache API docs.