From b591e87e499dac0ff566a7713930481514e64ff2 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sun, 24 Jan 2021 12:29:19 +0300 Subject: [PATCH 1/3] version upgrade to v2.7.0 --- package-lock.json | 140 ++++++++++++++++++---------------------------- package.json | 2 +- 2 files changed, 56 insertions(+), 86 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e35d88..35c41bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "nestjs-rate-limiter", - "version": "2.6.5", + "version": "2.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -631,93 +631,57 @@ } }, "@nestjs/common": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-7.5.4.tgz", - "integrity": "sha512-5Bz27EJz+g6fQ10P99Lovkyx++4w9a9TNUcnPXGloEeRFhAn0YeEM4c8Toj7uFq880xPoteBeZ9V2khOFWl4WQ==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-7.6.5.tgz", + "integrity": "sha512-WvBJd71ktaCRm9KTURVqn1YMyUzsOIkvezjP7WEpP9DVqQUOFVvn6/osJGZky/qL+zE4P7NBNyoXM94bpYvMwQ==", "dev": true, "requires": { - "axios": "0.21.0", + "axios": "0.21.1", "iterare": "1.2.1", "tslib": "2.0.3", - "uuid": "8.3.1" + "uuid": "8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } } }, "@nestjs/core": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-7.5.4.tgz", - "integrity": "sha512-OY7Kyne0mLoNlCodpT4gENISxMLnEmaUGBqPdqX5b3tZxh/NXeFBS5+1fJ/T2f4in+srM4cNioxDNUzRtTJsBw==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-7.6.5.tgz", + "integrity": "sha512-syRpXT09RDMySs1BLQSXJfq1NXGfG4VmF9hZYGef+/QWqTRfSMEDEH5MsCCLt2lK3AZnOXE9BQwWKeNBhKLplA==", "dev": true, "requires": { - "@nuxtjs/opencollective": "0.2.2", + "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.0.7", "iterare": "1.2.1", - "object-hash": "2.0.3", + "object-hash": "2.1.1", "path-to-regexp": "3.2.0", "tslib": "2.0.3", - "uuid": "8.3.1" + "uuid": "8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } } }, "@nuxtjs/opencollective": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.2.2.tgz", - "integrity": "sha512-69gFVDs7mJfNjv9Zs5DFVD+pvBW+k1TaHSOqUWqAyTTfLcKI/EMYQgvEvziRd+zAFtUOoye6MfWh0qvinGISPw==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", + "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", "dev": true, "requires": { - "chalk": "^2.4.1", - "consola": "^2.3.0", - "node-fetch": "^2.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.1" } }, "@sinonjs/commons": { @@ -1028,9 +992,9 @@ "dev": true }, "axios": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz", - "integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", "dev": true, "requires": { "follow-redirects": "^1.10.0" @@ -1921,9 +1885,9 @@ } }, "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", + "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", "dev": true }, "for-in": { @@ -1965,9 +1929,9 @@ "dev": true }, "fsevents": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.2.1.tgz", - "integrity": "sha512-bTLYHSeC0UH/EFXS9KqWnXuOl/wHK5Z/d+ghd5AsFMYN7wIGkUCOJyzy88+wJKkZPGON8u4Z9f6U4FdgURE9qA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz", + "integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==", "dev": true, "optional": true }, @@ -2049,7 +2013,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true + "dev": true, + "optional": true }, "har-schema": { "version": "2.0.0", @@ -2377,6 +2342,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "optional": true, "requires": { "is-docker": "^2.0.0" } @@ -3342,6 +3308,7 @@ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", "dev": true, + "optional": true, "requires": { "growly": "^1.3.0", "is-wsl": "^2.2.0", @@ -3356,6 +3323,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "optional": true, "requires": { "isexe": "^2.0.0" } @@ -3441,9 +3409,9 @@ } }, "object-hash": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", - "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.1.1.tgz", + "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==", "dev": true }, "object-visit": { @@ -4144,7 +4112,8 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true + "dev": true, + "optional": true }, "signal-exit": { "version": "3.0.3", @@ -4774,7 +4743,8 @@ "version": "8.3.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "dev": true + "dev": true, + "optional": true }, "v8-to-istanbul": { "version": "7.0.0", diff --git a/package.json b/package.json index b634a17..9e7f66a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nestjs-rate-limiter", - "version": "2.6.5", + "version": "2.7.0", "description": "Highly configurable rate limiter library", "repository": { "type": "git", From 2035b9db8a0d9cd0590f3f5411a7bdd60724535b Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sun, 24 Jan 2021 12:29:52 +0300 Subject: [PATCH 2/3] add usage explanations of customResponseSchema --- README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be36396..43b14ae 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,12 @@ public async signUp() { ```ts import { RateLimit } from 'nestjs-rate-limiter'; -@RateLimit({ keyPrefix: () => programmaticFuncThatReturnsValue(), points: 1, duration: 60, errorMessage: 'You can only request 1 in a minute by giving access token' }) +@RateLimit({ + keyPrefix: () => programmaticFuncThatReturnsValue(), + points: 1, + duration: 60, + customResponseSchema: () => { return { timestamp: '1611479696', message: 'Request has been blocked' }} +}) @Get('/example') public async example() { console.log('hello'); @@ -186,7 +191,8 @@ The usage of the limiter options is as in the code block below. For an explanati execEvenlyMinDelayMs: undefined, indexKeyPrefix: {}, maxQueueSize: 100, - errorMessage: 'Rate limit exceeded' + errorMessage: 'Rate limit exceeded', + customResponseSchema: undefined }), ], providers: [ @@ -431,6 +437,13 @@ GraphQLModule.forRoot({ errorMessage option can change the error message of rate limiter exception. + #### ● customResponseSchema + Default: undefined +
+ Type: string +
+ + customResponseSchema option allows to provide customizable response schemas # Benchmarks 1000 concurrent clients with maximum 2000 requests per sec during 30 seconds. From 498a8291e9be264518450db006f37c7fd94b14b1 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sun, 24 Jan 2021 12:30:07 +0300 Subject: [PATCH 3/3] provide customResponseSchema feature --- lib/default-options.spec.ts | 1 + lib/default-options.ts | 3 ++- lib/rate-limiter.interceptor.ts | 5 +++-- lib/rate-limiter.interface.ts | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/default-options.spec.ts b/lib/default-options.spec.ts index c59906b..8287937 100644 --- a/lib/default-options.spec.ts +++ b/lib/default-options.spec.ts @@ -29,5 +29,6 @@ describe('defaultRateLimiterOptions', () => { expect(Object.keys(defaultRateLimiterOptions.indexKeyPrefix).length).toBe(0) expect(defaultRateLimiterOptions.maxQueueSize).toBe(100) expect(defaultRateLimiterOptions.errorMessage).toBe('Rate limit exceeded') + expect(defaultRateLimiterOptions.customResponseSchema).toBeUndefined() }) }) diff --git a/lib/default-options.ts b/lib/default-options.ts index 4023959..a4edfdc 100644 --- a/lib/default-options.ts +++ b/lib/default-options.ts @@ -24,5 +24,6 @@ export const defaultRateLimiterOptions: RateLimiterOptions = { execEvenlyMinDelayMs: undefined, indexKeyPrefix: {}, maxQueueSize: 100, - errorMessage: 'Rate limit exceeded' + errorMessage: 'Rate limit exceeded', + customResponseSchema: undefined } diff --git a/lib/rate-limiter.interceptor.ts b/lib/rate-limiter.interceptor.ts index 102c552..9e31c9c 100644 --- a/lib/rate-limiter.interceptor.ts +++ b/lib/rate-limiter.interceptor.ts @@ -191,8 +191,9 @@ export class RateLimiterInterceptor implements NestInterceptor { } } catch (rateLimiterResponse) { response.header('Retry-After', Math.ceil(rateLimiterResponse.msBeforeNext / 1000)) - if (typeof this.options.createErrorBody === 'function') { - throw new HttpException(this.options.createErrorBody(rateLimiterResponse), HttpStatus.TOO_MANY_REQUESTS) + if (typeof this.spesificOptions?.customResponseSchema === 'function' || typeof this.options.customResponseSchema === 'function') { + var errorBody = this.spesificOptions?.customResponseSchema || this.options.customResponseSchema; + throw new HttpException(errorBody(rateLimiterResponse), HttpStatus.TOO_MANY_REQUESTS) } else { throw new HttpException(this.spesificOptions?.errorMessage || this.options.errorMessage, HttpStatus.TOO_MANY_REQUESTS) } diff --git a/lib/rate-limiter.interface.ts b/lib/rate-limiter.interface.ts index 02629e4..e61b866 100644 --- a/lib/rate-limiter.interface.ts +++ b/lib/rate-limiter.interface.ts @@ -27,7 +27,7 @@ export interface RateLimiterOptions { indexKeyPrefix?: {} maxQueueSize?: number errorMessage?: string - createErrorBody?: (rateLimiterResponse: RateLimiterRes) => {} + customResponseSchema?: (rateLimiterResponse: RateLimiterRes) => {} } export interface RateLimiterOptionsFactory {