Introduction
Rate limiting is a crucial feature for APIs to control traffic and prevent abuse. In this tutorial, we will explore how to implement rate limiting in a NestJS application using the latest NestJS and TypeScript syntax.
Getting Started
Before we dive into rate limiting, ensure you have a NestJS project set up. If you need to create a new project, run the following command:
nest new project-name
Next, navigate to the project directory:
cd project-name
Installing nestjs-rate-limiter
To implement rate limiting, we’ll need to install the nestjs-rate-limiter
package:
npm install nestjs-rate-limiter
Basic Rate Limiting
The simplest form of rate limiting can be applied application-wide. Import the RateLimiterModule
in your app.module.ts
:
import { RateLimiterModule } from 'nestjs-rate-limiter';
@Module({
imports: [
RateLimiterModule.register({
points: 5, // Number of points
duration: 60, // Per second(s)
}),
],
// ... other parts of the module
})
export class AppModule {}
This configuration will limit the entire application to five requests per minute for each IP address.
Controller-Specific Rate Limiting
To apply rate limiting on a specific controller, use the RateLimiterInterceptor
:
import { RateLimiterInterceptor } from 'nestjs-rate-limiter';
import { UseInterceptors } from '@nestjs/common';
@Controller('specific')
@UseInterceptors(RateLimiterInterceptor)
export class SpecificController {
// ... controller methods
}
Customizing Rate Limiting
Rate limiting can be customized with a variety of options. For instance, changing the key prefix:
RateLimiterModule.register({
keyPrefix: 'my-prefix', // custom prefix for rate limiting keys
// ... other options
})
Or configuring rate limiting based on the method type:
@UseInterceptors(new RateLimiterInterceptor({
points: 3,
duration: 60,
method: RequestMethod.POST,
}))
public create() {
// POST method-specific handling
}
This will limit the POST requests to three per minute.
Async Options
For more dynamic configurations, you may want to use the registerAsync
method, which allows you to use factory functions, existing configuration, or async providers:
@Module({
imports: [
RateLimiterModule.registerAsync({
useFactory: () => ({
points: 10,
duration: 60,
}),
// Alternatively useExisting or useClass
}),
],
})
export class AppModule {}
Rate Limiting in Microservices
If your NestJS application consists of microservices, you might need to consider a distributed rate limiting solution using a storage, like Redis:
RateLimiterModule.register({
storeType: 'redis',
redis: new Redis(), // Redis instance
points: 10,
duration: 60,
})
This configuration leverages Redis to rate limit your microservices in a distributed manner.
Handling Rate Limiting Responses
In the event that a limit is exceeded, a 429 Too Many Requests
HTTP response is typically returned. You can customize the rate limit exceed message using the exceptionFactory
option:
RateLimiterModule.register({
// ... other options
exceptionFactory: (errors) => new MyCustomException(errors),
})
Monitoring and Logging
Monitoring rate limit status can be essential for debugging. You can access rate limit information and create logs using interceptors or middleware as shown:
@Injectable()
export class RateLimitInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable {
const rateLimitInfo = context.switchToHttp().getResponse().getHeaders()['retry-after'];
// log the rateLimitInfo using your preferred logger
return next.handle();
}
}
Testing Rate Limiting
When integrating rate limiting, tests play a vital role to ensure functionality. Use libraries like supertest
to automate testing of rate limits:
describe('Rate Limited Endpoint', () => {
it('should return 429 status after rate limit exceeded', async () => {
const server = app.getHttpServer();
for (let i = 0; i <= 5; i++) {
const response = await request(server).get('/rate-limited-endpoint');
if (i === 5) {
expect(response.status).toBe(429);
}
}
});
});
Conclusion
In conclusion, NestJS provides an elegant and scalable way to implement rate limiting. By using the nestjs-rate-limiter
package, we can easily apply rate limits to our entire application, specific routes, or controllers, and customize our configuration to fit the needs of our project. With proper testing and logging, rate limiting can help maintain API stability and prevent abuse, ensuring a reliable service for users.