Skip to main content

Cache middlewares

Initial configuration​

To begin using the cache middlewares, you'll need to create and configure a CacheResolver instance:

./samples/cache.ts
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​

./samples/with-cache-factory.ts
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.

info

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​

./samples/with-invalidation.ts
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.

info

Here is a complete list of settings for the withInvalidation function.

Settings​

OptionTypeDescription
keyInvocable<TParameters, string>A function (or invocable object) that produces the cache key from the wrapped function's arguments
shouldInvalidateInvocable<[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.