Gathering detailed insights and metrics for nest-ratelimiter
Gathering detailed insights and metrics for nest-ratelimiter
npm install nest-ratelimiter
Typescript
Module System
Min. Node Version
Node Version
NPM Version
0.4.0: nestjs 11 support
Published on 23 Jan 2025
0.3.3: fix createErrorBody usage
Published on 23 Jun 2023
0.3.2: fix headers parsing
Published on 22 Jun 2023
0.3.1: fix packaging
Published on 20 Jun 2023
0.3.0: refactor; add service; update ci, deps, docs
Published on 20 Jun 2023
0.2.0: drop nestjs-redis as dep, add nestjs6+ support, move ratelimiter as peerDep
Published on 31 Aug 2021
TypeScript (86.77%)
JavaScript (13.23%)
Total Downloads
97,262
Last Day
61
Last Week
643
Last Month
1,804
Last Year
9,818
54 Stars
1,543 Commits
6 Forks
3 Watching
1 Branches
3 Contributors
Minified
Minified + Gzipped
Latest Version
0.4.0
Package Id
nest-ratelimiter@0.4.0
Unpacked Size
38.13 kB
Size
10.51 kB
File Count
29
NPM Version
10.9.2
Node Version
22.13.0
Publised On
23 Jan 2025
Cumulative downloads
Total Downloads
Last day
-26.5%
61
Compared to previous day
Last week
80.1%
643
Compared to previous week
Last month
143.5%
1,804
Compared to previous month
Last year
-75.8%
9,818
Compared to previous year
5
32
The most flexible NestJS rate limiter based on Redis (rate limit against not only req path but req body to block distributed brute force attacks).
1npm i nest-ratelimiter ratelimiter @types/ratelimiter
If you want to use the default response when reaching a limit (text: "Rate limit exceeded, retry in human readable time value") also install ms
.
1npm i nest-ratelimiter ratelimiter @types/ratelimiter ms
Let's start with controllers. Controllers are the places where you set parameters for the rate-limiter guard. You can set parameters for an entire controller or handler. Also, you can override the parameters of an entire controller by providing parameters for a specific handler. And finally, you can set several parameters for multi-checking.
1import { RateLimiter, LimiterInfo } from 'nest-ratelimiter'; 2 3// Let's define several functions that returns the identifier 4// to limit against. 5 6// This is functions for limiting requests by IP 7function getRequestIP(ctx: ExecutionContext) { 8 const request = ctx.switchToHttp().getRequest(); 9 return request.ip; 10} 11 12// Also you can limit every path separately 13function getRequestIPAndPath(ctx: ExecutionContext) { 14 const request = ctx.switchToHttp().getRequest(); 15 return `${request.ip}:${request.path}`; 16} 17 18// For blocking brute force attacks on login 19// you can return `login` value as identifier 20function getRequestBodyLogin(ctx: ExecutionContext) { 21 const request = ctx.switchToHttp().getRequest(); 22 return request.body.login; 23} 24 25// Now let's setup controller 26 27@Controller('/') 28// set params for entire controller 29@RateLimiter({ getId: getRequestIP }) 30class TestController { 31 // without providing params for specific handler 32 // it will inherit params of entire controller 33 @Get('some-api') 34 someApi() { 35 // ... 36 } 37 38 @Get('some-other-api') 39 // override params for specific handler 40 @RateLimiter({ 41 getId: getRequestIPAndPath, 42 max: 10, 43 duration: 10000, 44 }) 45 someOtherApi() { 46 // ... 47 } 48 49 @Get('one-more-api') 50 // turn off rate limiter for specific handler 51 @RateLimiter(false) 52 oneMoreApi() { 53 // ... 54 } 55 56 @Get('login') 57 // override params for specific handler 58 // by providing several params 59 @RateLimiter( 60 { 61 getId: getRequestIPAndPath, 62 max: 3, 63 duration: 60 * 60 * 1000, 64 }, 65 { 66 getId: getRequestBodyLogin, 67 max: 3, 68 duration: 60 * 60 * 1000, 69 // this is default `createErrorBody` function 70 // but you can set your own 71 createErrorBody: (limit: LimiterInfo) => { 72 const delta = limit.reset * 1000 - Date.now(); 73 // ms is imported from `ms` module 74 const readable = ms(delta, { long: true }); 75 return 'Rate limit exceeded, retry in ' + readable; 76 }, 77 }, 78 ) 79 login(creds: CredsDto) { 80 // ... 81 } 82}
Please, check out the docs of ratelimiter npm module for a better understanding of @RateLimiter
configuration.
Another feature is using rate limiting in complex scenarios when id
could not be retrieved from request context. For example when it's required to make a request for id in 3rd party systems:
1import { 2 RATE_LIMITER_ASSERTER_TOKEN, 3 RateLimiterAsserter, 4 setHeaders, 5} from 'nest-ratelimiter' 6 7@Controller('/') 8class TestController { 9 constructor( 10 @Inject(RATE_LIMITER_ASSERTER_TOKEN) 11 private asserter: RateLimiterAsserter, 12 private db: DB; 13 ) {} 14 15 @Get('some-api') 16 someApi( 17 @Res({ passthrough: true }) response: any 18 ) { 19 const id = await this.db.getId(); 20 21 // this potentially throws `RateLimiterError` which is handled by internal 22 // filter and mapped to `TooManyRequestsException`. If that doesn't fit your 23 // needs, semply use filters, interceptors, try/catch to handle those errors 24 const limiterInfo = this.asserter.assert({ 25 id, 26 max: 10, 27 duration: 24 * 60 * 60 * 1000, 28 }); 29 30 // In this simple example limiterInfo is retrieved in controller and 31 // `X-RateLimit-...` headers could be easily set with `setHeaders` function. 32 // In a real world scenario this is done on a services layer and in a such 33 // case limiterInfo should be passed back to a controller where there is an 34 // access to underlying framework's response object. But this is optional 35 // and only required if there is a need for such headers in a positive case. 36 setHeaders(response, limiterInfo); 37 } 38}
Let's move to module registration.
As nest-ratelimiter
is using Redis as a data storage you have to provide an instance of Redis
client (redis
or ioredis
). As Redis client instantiation is out of the scope of this package, you can find something that fits your needs on npm or create your own module for NestJS. Here we will show two examples: with redis and nestjs-redis modules:
1import { RedisModule } from 'nestjs-redis';
2import { RateLimiterModule, LimiterInfo } from 'nest-ratelimiter';
3
4@Module({
5 imports: [
6
7 // redis example
8
9 RateLimiterModule.forRoot({
10
11 // The only required field is `db` (redis client), all the rest fields
12 // will be used as defaults for `@RateLimiter(...)` and RateLimiterAsserter
13 db: require("redis").createClient()
14
15 }),
16
17 // nestjs-redis example
18
19 RateLimiterModule.forRootAsync({
20
21 // 1 Register third-party module that provides `redis` or `ioredis` client
22 imports: [
23 RedisModule.register({
24 host: process.env.REDIS_HOST,
25 port: parseInt(process.env.REDIS_PORT),
26 db: parseInt(process.env.REDIS_DB),
27 }),
28 ],
29
30 // 2 And then inject redis client provider
31 inject: [RedisService],
32
33 // 3. build and return `RateLimiterModuleParams` from factory
34 useFactory: async (redisService: RedisService) => {
35
36 // You can set default fields for every @RateLimiter and then you don't
37 // have to copy-paste your params on entire codebase.
38
39 // IF YOU SET `getId` HERE, THEN ALL CONTROLLERS (EVEN THOSE WITHOUT
40 // @RateLimiter GUARD) WILL USE THIS FUNCTION BY DEFAULT. IF IN THAT
41 // CASE YOU NEED TO TURN OFF RATE LIMITER ON SOME SPECIFIC HANDLER OR
42 // CONTROLLER JUST USE `@RateLimiter(false)`
43
44 return {
45 db: redisService.getClient(),
46 max: 10,
47 duration: 10000,
48 getId: getRequestIPAndPath;
49 createErrorBody: (limit: LimiterInfo) => ({
50 error: {
51 code: 'MY-RATE-LIMIT-ERROR-CODE',
52 params: limit,
53 },
54 }),
55 };
56 },
57
58 }),
59 ],
60 controllers: [TestController],
61})
62class TestModule {}
This nest-ratelimiter
is using TJ's ratelimiter package underhood, so it allows the creation of a flexible strategy for limiting not only per request path but per headers or body values or even asynchronously computed values on a services layer. It stores data only in redis
. If you need another store you can look at nestjs-rate-limiter, but it allows the use of strategies based on a request path only. Also, there is an example in official docs with setting up express-rate-limit middleware.
app.useGlobalGuards
as now it's set automaticallynestjs-redis
was moved from dependencies, now you are free to use any redis module that fit your needs, but you have to set new field RateLimiterModuleParams.db
that should be redis
or ioredis
instance.ratelimiter
(with @types/ratelimiter
) was moved to peer dependencies. If you are using npm@7
it will install it automatically, either way you should install it manually.No vulnerabilities found.
Reason
13 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Reason
no binaries found in the repo
Reason
no dangerous workflow patterns detected
Reason
license file detected
Details
Reason
1 existing vulnerabilities detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 4
Details
Reason
Found 0/3 approved changesets -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2025-01-27
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More