Skip to main content

DI Integration

The rateLimiterFactoryResolverDiFactory function creates an IRateLimiterFactoryResolver whose underlying resolver is resolved from a DI container.

The returned proxy implements both IRateLimiterFactoryResolver and IRateLimiterFactory:

  • use(adapterName?) selects an adapter on the resolved RateLimiterFactoryResolver.
  • create(key, settings) creates a rate limiter through the resolver's default adapter.

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

Initial configuration​

Set up the memory and Redis rate-limiter adapters, create the container, then register the RateLimiterFactoryResolver and wrap it with rateLimiterFactoryResolverDiFactory:

1. Set up the memory rate-limiter adapter​

./samples/memory-rate-limiter-adapter.ts
import { DatabaseRateLimiterAdapter } from "eridu-tech/rate-limiter/database-rate-limiter-adapter";
import { MemoryRateLimiterStorageAdapter } from "eridu-tech/rate-limiter/memory-rate-limiter-storage-adapter";

export const memoryRateLimiterAdapter = new DatabaseRateLimiterAdapter({
adapter: new MemoryRateLimiterStorageAdapter(),
});

2. Set up the Redis rate-limiter adapter​

./samples/redis-rate-limiter-adapter.ts
import { RedisRateLimiterAdapter } from "eridu-tech/rate-limiter/redis-rate-limiter-adapter";
import { Redis } from "ioredis";

export const redisRateLimiterAdapter = new RedisRateLimiterAdapter({
database: new Redis("YOUR_REDIS_CONNECTION_STRING"),
});

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 rate-limiter factory resolver​

./samples/rate-limiter-factory-resolver-di-factory.ts
import { RateLimiterFactoryResolver } from "eridu-tech/rate-limiter";
import { ProxyRateLimiterFactoryResolver } from "eridu-tech/rate-limiter/di";
import { container } from "./container.js";
import { memoryRateLimiterAdapter } from "./memory-rate-limiter-adapter.js";
import { redisRateLimiterAdapter } from "./redis-rate-limiter-adapter.js";
import { SuperJsonSerde } from "eridu-tech/serde/super-json-serde";

type Adapters = "memory" | "redis";

const serde = new SuperJsonSerde();
const rateLimiterFactoryResolver = new RateLimiterFactoryResolver<Adapters>({
serde,
adapters: {
memory: memoryRateLimiterAdapter,
redis: redisRateLimiterAdapter,
},
defaultAdapter: "memory",
});

await rateLimiterFactoryResolver.init();

container.registerValue({
token: RateLimiterFactoryResolver,
value: rateLimiterFactoryResolver,
});

// Create the proxy before container.init()
export const rateLimiterFactory = new ProxyRateLimiterFactoryResolver<Adapters>(
{
container,
resolverToken: RateLimiterFactoryResolver,
},
);

await container.init();

Usage​

1. Using the default adapter​

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

// Uses the adapter configured as the default (memory)
await rateLimiterFactory
.create("shared-resource", {
limit: 10,
})
.runOrFail(async () => {
// code to run
});

2. Specifying an adapter explicitly​

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

// Uses the Redis adapter
await rateLimiterFactory
.use("redis")
.create("shared-resource", {
limit: 10,
})
.runOrFail(async () => {
// code to run
});

Using it with the middlewares​

Because the proxy implements IRateLimiterFactoryResolver, it can be passed straight to the rate-limiter middleware factories:

./samples/rate-limiter-factory-resolver-di-factory-with-middleware.ts
import { use } from "eridu-tech/middleware";
import { withRateLimiterFactory } from "eridu-tech/rate-limiter/middlewares";
import { rateLimiterFactory } from "./rate-limiter-factory-resolver-di-factory.js";

const withRateLimiter = withRateLimiterFactory(rateLimiterFactory);

const fetchHandler = async (request: Request): Promise<Response> => {
// ... handle the request
return new Response("OK");
};

const rateLimitedCall = use(
fetchHandler,
withRateLimiter.use("redis")({
key: ([req]) => `api:${String(req.headers.get("x-ip"))}`,
limit: 10,
}),
);

await rateLimitedCall(
new Request("/url", {
method: "POST",
}),
);

Further information​

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