Redis as custom storage for NestJS rate limiter
Node.js developer, creating tech content at https://sevic.dev
A rate limiter is a standard protection technique against brute force and DDoS attacks. NestJS provides a module for it, and the default storage is in-memory. Custom storage, Redis in this case, should be injected inside ThrottlerModule configuration.
Configuration
The configuration should contain
TTL (time to live) in seconds
maximum number of requests within TTL
Redis URL
// app.module.ts
import { APP_GUARD } from '@nestjs/core';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { ThrottlerStorageRedisService } from 'nestjs-throttler-storage-redis';
// ...
@Module({
imports: [
ThrottlerModule.forRootAsync({
inject: [CustomConfigService],
useFactory: (configService: CustomConfigService) => ({
ttl: configService.THROTTLER_TTL_SECONDS,
limit: configService.THROTTLER_LIMIT,
storage: new ThrottlerStorageRedisService(configService.REDIS_URL),
}),
}),
// ...
],
})
export class AppModule {}
API endpoints setup
Binding the throttler guard can be done in multiple ways.
- the guard is bound globally for every API endpoint.
// app.module
import { ThrottlerGuard } from '@nestjs/throttler';
// ...
@Module({
// ...
providers: [{
provide: APP_GUARD,
useClass: ThrottlerGuard,
}],
})
export class AppModule {}
- the global guard is overridden for the specific API endpoint with the
Throttledecorator.
import { Throttle } from '@nestjs/throttler';
// ...
@Controller('users')
export class UsersController {
@Throttle(USERS_THROTTLER_LIMIT, USERS_THROTTLER_TTL_SECONDS)
@Get()
async getUsers() {}
}
- the global guard is skipped for the specific API endpoint with the
SkipThrottledecorator.
import { SkipThrottle } from '@nestjs/throttler';
// ...
@Controller('posts')
export class PostsController {
@SkipThrottle()
@Get()
async getPosts() {}
}
Boilerplate
Here is the link to the boilerplate I use for the development.