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.
- 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 {}
- global guard is overridden for the specific API endpoint with the
Throttle
decorator.
import { Throttle } from '@nestjs/throttler';
// ...
@Controller('users')
export class UsersController {
@Throttle(USERS_THROTTLER_LIMIT, USERS_THROTTLER_TTL_SECONDS)
@Get()
async getUsers() {}
}
- global guard is skipped for the specific API endpoint with the
SkipThrottle
decorator.
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.