@routup/rate-limit
Version:
Routup rate limiter.
268 lines (186 loc) • 6.35 kB
Markdown
# @routup/rate-limit
[](https://badge.fury.io/js/@routup%2Frate-limit)
[](https://github.com/routup/plugins/actions/workflows/main.yml)
[](https://codecov.io/gh/routup/plugins)
[](https://snyk.io/test/github/routup/plugins)
[](https://conventionalcommits.org)
This is a rate-limiter middleware.
**Table of Contents**
- [Installation](#installation)
- [Documentation](#documentation)
- [Usage](#usage)
- [Store](#store)
- [Options](#options)
- [windowsMs](#windowms)
- [max](#max)
- [message](#message)
- [statusCode](#statuscode)
- [skipFailedRequest](#skipfailedrequest)
- [skipSuccessFulRequest](#skipsuccessfulrequest)
- [keyGenerator](#keygenerator)
- [handler](#handler)
- [skip](#skip)
- [requestWasSuccessful](#requestwassuccessful)
- [store](#store)
- [License](#license)
## Installation
```bash
npm install @routup/rate-limit --save
```
## Documentation
To read the docs, visit [https://routup.net](https://routup.net)
## Usage
```typescript
import {
App,
serve,
} from 'routup';
import { rateLimit } from '@routup/rate-limit';
const router = new App();
router.use(rateLimit({
// 15 minutes
windowMs: 15 * 60 * 1000,
// Limit each IP to 100 requests
// per `window` (here, per 15 minutes)
max: 100,
}));
serve(router, { port: 3000 });
```
### Store
To create a custom Store it is mandatory to extend the `Store` interface.
The following adapters are officially provided:
- [@routup/rate-limit-redis](https://www.npmjs.com/package/@routup/rate-limit-redis)
## Options
### `windowMs`
> `number`
Time frame for which requests are checked/remembered. Also used in the
`Retry-After` header when the limit is reached.
Defaults to `60000` ms (= 1 minute).
### `max`
> `number | function`
The maximum number of connections to allow during the `window` before rate
limiting the client.
Can be the limit itself as a number or a (sync/async) function that accepts the
routup `event` and then returns a number.
Defaults to `5`. Set it to `0` to disable the rate limiter.
An example of using a function:
```ts
const isPremium = async (ip: string) => {
// ...
}
const handler = createHandler({
// ...
max: async (event) => {
const ip = getRequestIP(event, { trustProxy: true }) || '127.0.0.1';
if (await isPremium(ip)) return 10
else return 5
},
})
```
### `message`
> `any`
The response body to send back when a client is rate limited.
May be a `string`, JSON object, or any other value.
It can also be a (sync/async) function that accepts the routup `event`
and then returns a `string`, JSON object or any other value.
Defaults to `'Too many requests, please try again later.'`
An example of using a function:
```ts
const isPremium = async (ip: string) => {
// ...
}
const handler = createHandler({
// ...
message: async (event) => {
const ip = getRequestIP(event, { trustProxy: true }) || '127.0.0.1';
if (await isPremium(ip)) {
return 'You can only make 10 requests every hour.'
}
return 'You can only make 5 requests every hour.'
},
})
```
### `statusCode`
> `number`
The HTTP status code to send back when a client is rate limited.
Defaults to `429` (HTTP 429 Too Many Requests - RFC 6585).
### `skipFailedRequest`
> `boolean`
When set to `true`, failed requests won't be counted. Request considered failed
when the `requestWasSuccessful` option returns `false`. By default, this means
requests fail when the response status >= 400.
Defaults to `false`.
### `skipSuccessfulRequest`
> `boolean`
If `true`, the library will (by default) skip all requests that are considered
'successful' by the `requestWasSuccessful` function. By default, this means requests
succeed when the response status code < 400.
Defaults to `false`.
### `keyGenerator`
> `function`
Method to generate custom identifiers for clients.
Should be a (sync/async) function that accepts the routup `event`
and then returns a string.
By default, the client's IP address is used:
```ts
import { getRequestIP } from 'routup';
const handler = createHandler({
// ...
keyGenerator: (event) => getRequestIP(event, { trustProxy: true }),
})
```
### `handler`
> `function`
Handler that sends back a response when a client is rate-limited.
By default, sends back the `statusCode` and `message` set via the `options`,
similar to this:
```ts
const handler = createHandler({
// ...
handler(event, options) {
event.response.status = options.statusCode;
return options.message;
}
})
```
### `skip`
> `function`
Function to determine whether this request counts towards a client's
quota. Should be a (sync/async) function that accepts the routup `event`
and then returns `true` or `false`.
Could also act as an allow list for certain keys:
```ts
const allowlist = ['192.168.0.56', '192.168.0.21']
const handler = createHandler({
// ...
skip: (event) => allowlist.includes(getRequestIP(event)),
})
```
By default, it skips no requests:
```ts
const handler = createHandler({
// ...
skip: (event) => false,
})
```
### `requestWasSuccessful`
> `function`
Method to determine whether the request counts as 'successful'. Used when
either `skipSuccessfulRequest` or `skipFailedRequest` is set to true. Should
be a function that accepts the routup `event` and the downstream `Response`
object and then returns `true` or `false`.
By default, requests with a response status code less than 400 are considered
successful:
```ts
const handler = createHandler({
// ...
requestWasSuccessful: (event, response) => response.status < 400,
})
```
### `store`
The `Store` to use to store the hit count for each client.
## License
Made with 💚
Published under [MIT License](./LICENSE).
This library is heavily inspired by
[express-rate-limit](https://www.npmjs.com/package/express-rate-limit).