UNPKG

@routup/rate-limit

Version:
268 lines (186 loc) 6.35 kB
# @routup/rate-limit [![npm version](https://badge.fury.io/js/@routup%2Frate-limit.svg)](https://badge.fury.io/js/@routup%2Frate-limit) [![main](https://github.com/routup/plugins/actions/workflows/main.yml/badge.svg)](https://github.com/routup/plugins/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/routup/plugins/branch/master/graph/badge.svg)](https://codecov.io/gh/routup/plugins) [![Known Vulnerabilities](https://snyk.io/test/github/routup/plugins/badge.svg)](https://snyk.io/test/github/routup/plugins) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](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).