Rate limiting is a technique used to control the rate at which requests can be made to an API or resources over a given time period.
It's a mechanism used to prevent abuse or excessive load on a system and to ensure that it operates within it's capacity and remains responsive and available to all users.
Rate limiting typically involves setting specific limits on the number of requests per unit of time.
e.g. An API might allow n number of requests for a specific user or IP address.
They are defined within specific time windows, such as per second, per minute, per hour and are enforced within these time periods.
When a client exceeds the limit, the server typically responds with an error response (HTTP 429 Too Many Requests) to inform the user that it should slow down and retry later.
Rate limiting is often used to prevent abuse, such as Distributed Denial of Service (DDoS) attacks, spamming, or scraping of data from websites. It helps ensure fair access to a resource.
Pre-requisites
First of all, we will need to make sure that we have the Nest.js CLI installed. This will allow us scaffold and maintain our project locally.
npm i -g @nestjs/cliSecondly, we will need to install the @nestjs/throttler package from NPM:
npm i --save @nestjs/throttlerOnce the installation is complete you can configure the package as shown below in app.module.ts
/* App.module.ts */
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';
@Module({
imports: [
ThrottlerModule.forRoot([
{
ttl: 10000,
limit: 2,
},
]),
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class AppModule {}
The above will set the global options for the ttl, the time to live in milliseconds, and the limit, the maximum number of requests within the ttl, for the routes of your application that are guarded.
Next we will need to define a provider using an object literal and associate it with the APP_GUARD from nestjs/core. This specifies that the ThrottlerGuard imported from nestjs/throttler should be used as a global guard for the entire application. Meaning that the rate limiting logic will be applied to all endpoints by default.
Meaning that the rate limiting logic will be applied to all endpoints by default.
By sending a Get request twice in 10 seconds to our home endpoint we should get back "Hello World" as a response from our API.
Once we send the third request in the same 10 second period we should get back the 429 Http Exception as shown below.
Great so we can see that it worked!
Well, that's easy too … all we do is import the @SkipThrottle decorator from @nestjs/throttler package and add that to our unthrottled endpoint "no-limit" as shown below.
/* App.controller.ts */
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { SkipThrottle } from '@nestjs/throttler';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@SkipThrottle()
@Get('no-limit')
getNoLimit(): string {
return 'No rate limit here!';
}
}
Another way to disable rate limiting is to add it to the app controller itself. This will now disable it for all endpoints under the app controller class.
/* App.controller.ts */
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { SkipThrottle } from '@nestjs/throttler';
@SkipThrottle()
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('no-limit')
getNoLimit(): string {
return 'No rate limit here!';
}
}
All we need to do is to import the Throttle decorator from nestjs/throttler and add that to our new endpoint "custom-limit" as shown below.
/* App.controller.ts */
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { SkipThrottle, Throttle } from '@nestjs/throttler';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@SkipThrottle()
@Get('no-limit')
getNoLimit(): string {
return 'No rate limit here!';
}
/*
-------------------------------------------------------------------
| We are overriding the default configuration in our app.module.ts |
| with a 1/10000 rate limit - Meaning 1 requset per 10 seconds |
-------------------------------------------------------------------
*/
@Throttle({ default: { limit: 1, ttl: 10000 } })
@Get('custom-limit')
customLimit(): string {
return 'This has a custom limit applied!';
}
}
And that's it!
Rate limiting is an essential part of designing and operating web services and APIs to ensure fair usage, protect against misuse, and maintain system stability and performance.