Skip to main content

DI Integration

The cacheResolverDiFactory function creates an ICacheResolver whose underlying resolver is resolved from a DI container.

The returned proxy implements both ICacheResolver and ICache:

  • use(adapterName?) selects an adapter on the resolved CacheResolver.
  • The ICache methods such as get, add and getOrAdd delegate to the resolver's default adapter.

The proxy is wired to the container during container.init(). Create it before calling init(); calling use() or a cache method before the container is initialized throws an error.

Initial configuration​

Set up the memory and Redis cache adapters, create the container, then register the CacheResolver and wrap it with cacheResolverDiFactory:

1. Set up the memory cache adapter​

./samples/memory-cache-adapter.ts
import { MemoryCacheAdapter } from "eridu-tech/cache/memory-cache-adapter";

export const memoryCacheAdapter = new MemoryCacheAdapter();

2. Set up the Redis cache adapter​

./samples/redis-cache-adapter.ts
import { RedisCacheAdapter } from "eridu-tech/cache/redis-cache-adapter";
import { SuperJsonSerde } from "eridu-tech/serde/super-json-serde";
import { Redis } from "ioredis";

export const redisCacheAdapter = new RedisCacheAdapter({
database: new Redis("YOUR_REDIS_CONNECTION_STRING"),
serde: new SuperJsonSerde(),
});

3. Create the dependency injection container​

./samples/container.ts
import { Container } from "eridu-tech/di";
import { ExecutionContext } from "eridu-tech/execution-context";
import { AlsExecutionContextAdapter } from "eridu-tech/execution-context/als-execution-context-adapter";

export const executionContext = new ExecutionContext(
new AlsExecutionContextAdapter(),
);
export const container = new Container({ executionContext });

4. Register and initialize the cache resolver​

./samples/cache-resolver-di-factory.ts
import { CacheResolver } from "eridu-tech/cache";
import { ProxyCacheResolver } from "eridu-tech/cache/di";
import { container } from "./container.js";
import { memoryCacheAdapter } from "./memory-cache-adapter.js";
import { redisCacheAdapter } from "./redis-cache-adapter.js";

type Adapters = "memory" | "redis";

const cacheResolver = new CacheResolver<Adapters>({
adapters: {
memory: memoryCacheAdapter,
redis: redisCacheAdapter,
},
defaultAdapter: "memory",
});

await cacheResolver.init();

container.registerValue({
token: CacheResolver,
value: cacheResolver,
});

// Create the proxy before container.init()
export const cache = new ProxyCacheResolver<Adapters>({
container,
resolverToken: CacheResolver,
});

await container.init();

Usage​

1. Using the default adapter​

./samples/cache-resolver-di-factory-default-adapter.ts
import { cache } from "./cache-resolver-di-factory.js";

// Uses the adapter configured as the default (memory)
await cache.add("user/jose@gmail.com", {
name: "Jose",
age: 20,
});

2. Specifying an adapter explicitly​

./samples/cache-resolver-di-factory-specific-adapter.ts
import { cache } from "./cache-resolver-di-factory.js";

// Uses the Redis adapter
await cache.use("redis").add("user/jose@gmail.com", {
name: "Jose",
age: 20,
});

Using it with the middlewares​

Because the proxy implements ICacheResolver, it can be passed straight to the cache middleware factories:

./samples/cache-resolver-di-factory-with-middleware.ts
import { withCacheFactory } from "eridu-tech/cache/middlewares";
import { use } from "eridu-tech/middleware";
import { TimeSpan } from "eridu-tech/time-span";
import { cache } from "./cache-resolver-di-factory.js";

const withCache = withCacheFactory(cache);

const fetchUser = async (userId: string): Promise<{ name: string }> => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
};

const cachedFetchUser = use(
fetchUser,
withCache.use("redis")({
key: ([userId]) => `user:${userId}`,
ttl: TimeSpan.fromMinutes(10),
}),
);

await cachedFetchUser("123");

Further information​

For further information refer to eridu-tech/cache API docs.