DEV Community

Željko Šević
Željko Šević

Posted on • Originally published at sevic.dev on

Redis as custom storage for NestJS rate limiter

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 {}
Enter fullscreen mode Exit fullscreen mode

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 {}
Enter fullscreen mode Exit fullscreen mode
  • 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() {}
}
Enter fullscreen mode Exit fullscreen mode
  • 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() {}
}
Enter fullscreen mode Exit fullscreen mode

Boilerplate

Here is the link to the boilerplate I use for the development.

Top comments (0)