### RedisStore child Example Usage Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Example showing how to create a child RedisStore with specific route options. ```javascript const parentStore = new RedisStore(false, false, redis, 'app-') // Creates store with key: 'app-GET/api/data-' const childStore = parentStore.child({ continueExceeding: false, exponentialBackoff: false, routeInfo: { method: 'GET', url: '/api/data' } }) ``` -------------------------------- ### Install @fastify/rate-limit Source: https://github.com/fastify/fastify-rate-limit/blob/main/README.md Install the package using npm. ```bash npm i @fastify/rate-limit ``` -------------------------------- ### Registering a Custom Store with Fastify Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Example of how to register Fastify Rate Limit with a custom store implementation. ```javascript await fastify.register(fastifyRateLimit, { max: 100, timeWindow: '1 minute', store: CustomStore }) ``` -------------------------------- ### RedisStore incr Example Usage Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Example demonstrating how to use the incr method of RedisStore with ioredis. ```javascript const Redis = require('ioredis') const redis = new Redis({ host: 'localhost', port: 6379, connectTimeout: 500, maxRetriesPerRequest: 1 }) const store = new RedisStore(false, false, redis, 'app-rate-limit-') store.incr('user-123', (err, result) => { if (err) { console.error('Redis error:', err) return } console.log(`Requests: ${result.current}, TTL: ${result.ttl}ms`) }, 60000, 100) ``` -------------------------------- ### GraphQL Rate Limiting Example Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/00-index.md Demonstrates how to integrate Fastify Rate Limit with GraphQL endpoints, creating a limiter instance and checking for exceeded limits. ```javascript const limiter = fastify.createRateLimit() fastify.post('/graphql', async (request, reply) => { const limit = await limiter(request) if (limit.isExceeded) { return reply.code(429).send('Rate limited') } return executeGraphQL(request) }) ``` -------------------------------- ### Register Fastify Rate Limit Plugin Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/01-plugin-registration.md Register the @fastify/rate-limit plugin with default options. This example shows basic setup for global rate limiting. ```javascript import Fastify from 'fastify' import fastifyRateLimit from '@fastify/rate-limit' const fastify = Fastify() // Register with default options await fastify.register(fastifyRateLimit, { max: 100, timeWindow: '1 minute' }) fastify.get('/', (request, reply) => { reply.send({ hello: 'world' }) }) await fastify.listen({ port: 3000 }) ``` -------------------------------- ### Registering Fastify Rate Limit Plugin Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/01-plugin-registration.md Example of registering the rate limit plugin with global options and creating a custom limiter instance for specific routes. ```javascript import Fastify from 'fastify' import fastifyRateLimit from '@fastify/rate-limit' const fastify = Fastify() await fastify.register(fastifyRateLimit, { global: false, max: 100, timeWindow: '1 minute' }) // Create a limiter with global options const checkLimit = fastify.createRateLimit() fastify.post('/graphql', async (request, reply) => { const limit = await checkLimit(request) if (!limit.isAllowed && limit.isExceeded) { return reply.code(429).send({ error: 'Rate limit exceeded', retryAfter: limit.ttlInSeconds }) } // Process GraphQL query return reply.send({ data: 'result' }) }) // Create a limiter with custom options const strictLimit = fastify.createRateLimit({ max: 10, timeWindow: 60000 }) fastify.post('/login', async (request, reply) => { const limit = await strictLimit(request) if (limit.isExceeded) { return reply.code(429).send('Too many login attempts') } // Process login return reply.send({ token: 'xxx' }) }) ``` -------------------------------- ### Plugin Registration with Redis and Custom Headers Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Example of registering the Fastify Rate Limit plugin globally, configuring Redis for distributed limiting, and specifying custom headers. ```typescript await fastify.register(fastifyRateLimit, { global: true, max: 1000, timeWindow: '1 minute', redis: redisClient, nameSpace: 'myapp-', enableDraftSpec: false, addHeaders: { 'x-ratelimit-limit': true, 'x-ratelimit-remaining': true, 'x-ratelimit-reset': true, 'retry-after': true } }) ``` -------------------------------- ### Integrate PostgreSQL for Database-Backed Rate Limiting Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Utilize a PostgreSQL database as a store for rate limiting. This example defines a `PostgresStore` class with an `incr` method to manage request counts and reset times, then registers it with Fastify. ```javascript class PostgresStore { constructor(options) { this.pool = options.pool this.options = options } incr(key, callback, timeWindow, max) { const now = Date.now() const windowStart = now - timeWindow this.pool.query( `INSERT INTO rate_limits (key, count, reset_at) VALUES ($1, 1, $2) ON CONFLICT (key) DO UPDATE SET count = CASE WHEN rate_limits.reset_at < $3 THEN 1 ELSE rate_limits.count + 1 END, reset_at = CASE WHEN rate_limits.reset_at < $3 THEN $2 ELSE rate_limits.reset_at END RETURNING count, reset_at`, [key, new Date(now + timeWindow), new Date(windowStart)] ) .then(result => { const row = result.rows[0] const ttl = Math.max(0, row.reset_at - now) callback(null, { current: row.count, ttl }) }) .catch(err => callback(err)) } child(routeOptions) { return new PostgresStore(Object.assign({}, this.options, routeOptions)) } } const { Pool } = require('pg') const pool = new Pool() await fastify.register(fastifyRateLimit, { store: PostgresStore, pool, max: 100 }) ``` -------------------------------- ### Route-level Rate Limiting Usage Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Example demonstrating how to configure rate limiting for a specific route using `config.rateLimit`. ```typescript fastify.get('/api', { config: { rateLimit: { max: 100, timeWindow: '1 minute', onExceeding: (req, key) => { console.log(`Approaching limit for ${key}`) }, onExceeded: (req, key) => { console.log(`Rate limited: ${key}`) }, onBanReach: (req, key) => { console.log(`Banned: ${key}`) } } } }, handler) ``` -------------------------------- ### Registering Rate Limiter with Custom Hook Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Example of registering the rate limiter plugin with a specific hook. This example sets the hook to 'preHandler' to apply rate limiting after validation. ```typescript await fastify.register(fastifyRateLimit, { hook: 'preHandler', // Check rate limit after validation max: 100 }) ``` -------------------------------- ### Custom Store Implementation for Rate Limiting Source: https://github.com/fastify/fastify-rate-limit/blob/main/README.md Create a custom store to manage rate limiting data. The example defines a `CustomStore` with `incr` and `child` methods, demonstrating how to integrate it with the rate limit plugin. ```javascript function CustomStore (options) { this.options = options this.current = 0 } CustomStore.prototype.incr = function (key, cb, timeWindow, max) { this.current++ cb(null, { current: this.current, ttl: timeWindow - (this.current * 1000) }) } CustomStore.prototype.child = function (routeOptions) { // We create a merged copy of the current parent parameters with the specific // route parameters and pass them into the child store. const childParams = Object.assign(this.options, routeOptions) const store = new CustomStore(childParams) // Here is where you may want to do some custom calls on the store with the information // in routeOptions first... // store.setSubKey(routeOptions.method + routeOptions.url) return store } await fastify.register(import('@fastify/rate-limit'), { /* ... */ store: CustomStore }) ``` -------------------------------- ### Manual Rate Limiter Usage Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Example of creating and using a manual rate limiter with custom options. This demonstrates setting max requests, time window, and a custom key generator. ```typescript const checkLimit = fastify.createRateLimit({ max: 50, timeWindow: '5 minutes', keyGenerator: (req) => req.headers['authorization'] || req.ip }) fastify.post('/api', async (request, reply) => { const limit = await checkLimit(request) if (!limit.isAllowed && limit.isExceeded) { return reply.code(429).send('Rate limited') } }) ``` -------------------------------- ### Dynamic Allow List Configuration Source: https://github.com/fastify/fastify-rate-limit/blob/main/README.md Dynamically determine if a request should be allowed based on request headers. This example allows requests with a specific 'internal-usage' client ID to bypass rate limiting. ```javascript await fastify.register(import('@fastify/rate-limit'), { /* ... */ allowList: function (request, key) { return request.headers['x-app-client-id'] === 'internal-usage' } }) ``` -------------------------------- ### LocalStore Entry Structure Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/07-lifecycle-and-hooks.md The in-memory LocalStore maintains request count, time-to-live, and the start time of the current window for each entry. ```javascript // Entry structure: { current: 5, // Current request count ttl: 55000, // Remaining milliseconds iterationStartMs: 1234567890 // Window start timestamp } ``` -------------------------------- ### Fallback on Redis Failure Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md This example demonstrates graceful degradation by configuring rate limiting to continue functioning even if Redis fails. It uses `skipOnError: true` and monitors Redis health. ```javascript let redisHealthy = true const redis = new Redis({ host: 'localhost', enableOfflineQueue: false, enableReadyCheck: false }) redis.on('error', () => { redisHealthy = false }) redis.on('ready', () => { redisHealthy = true }) await fastify.register(fastifyRateLimit, { redis, skipOnError: true // Continue without limiting if Redis fails }) fastify.get('/health', (req, reply) => { reply.send({ status: 'ok', rateLimitStore: redisHealthy ? 'redis' : 'disabled' }) }) ``` -------------------------------- ### Dynamic Max Requests Based on Key Source: https://github.com/fastify/fastify-rate-limit/blob/main/README.md Configure dynamic maximum request limits that change based on the generated key. This example sets a higher limit for 'pro' keys and a lower limit for others within the same time window. ```javascript fastify.register(rateLimit, { /* ... */ keyGenerator (request) { return request.headers['service-key'] }, max: async (request, key) => { return key === 'pro' ? 3 : 2 }, timeWindow: 1000 }) ``` -------------------------------- ### Configure Redis Cluster for Distributed Rate Limiting Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Set up distributed rate limiting using a Redis Cluster. This example connects to a Redis cluster and applies a rate limit of 10000 requests per minute across all nodes. ```javascript const Redis = require('ioredis') const redisCluster = new Redis.Cluster([ { host: '127.0.0.1', port: 7000 }, { host: '127.0.0.1', port: 7001 }, { host: '127.0.0.1', port: 7002 } ]) await fastify.register(fastifyRateLimit, { redis: redisCluster, max: 10000, timeWindow: '1 minute' }) ``` -------------------------------- ### Implement MongoDB Store for Rate Limiting Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Use MongoDB as a backend store for rate limiting. This example defines a `MongoStore` class with an `incr` method that uses `findOneAndUpdate` to atomically increment counts and update reset times in a 'rate_limits' collection. ```javascript class MongoStore { constructor(options) { this.db = options.db this.collection = options.db.collection('rate_limits') this.options = options } incr(key, callback, timeWindow, max) { const now = Date.now() const windowStart = now - timeWindow this.collection.findOneAndUpdate( { key }, { $set: { key, resetAt: new Date(now + timeWindow) }, $cond: { if: { $lt: ['$resetAt', new Date(windowStart)] }, then: { $set: { count: 1 } }, else: { $inc: { count: 1 } } } }, { upsert: true, returnDocument: 'after' } ) .then(result => { const ttl = Math.max(0, result.value.resetAt - now) callback(null, { current: result.value.count, ttl }) }) .catch(err => callback(err)) } child(routeOptions) { return new MongoStore(Object.assign({}, this.options, routeOptions)) } } ``` -------------------------------- ### LocalStore Internal State Structure Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Illustrates the internal structure of entries stored in the LocalStore's LRU cache, including request count, time-to-live, and window start time. ```javascript { current: number, // Current request count ttl: number, // Remaining time in milliseconds iterationStartMs: number // Timestamp when window started } ``` -------------------------------- ### Load Testing with Autocannon Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md This example shows how to use the autocannon tool to perform load testing against a Fastify API endpoint protected by rate limiting. It logs the number of rate limit violations (429 status codes) encountered during the test. ```javascript const autocannon = require('autocannon') autocannon({ url: 'http://localhost:3000/api', connections: 100, pipelining: 1, duration: 30, requests: [{ path: '/api', method: 'GET' }] }, (err, results) => { console.log('Rate limit violations:', results.statusCodeStats['429'] || 0) }) ``` -------------------------------- ### Rate Limit Login Attempts by Username Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Configure rate limiting specifically for login attempts, using the username as the key to prevent brute-force attacks. This example sets a limit of 5 attempts per 15 minutes and logs potential attacks. ```javascript await fastify.register(fastifyRateLimit, { global: false, max: 5, timeWindow: '15 minutes' }) fastify.post('/login', { config: { rateLimit: { max: 5, timeWindow: '15 minutes', keyGenerator: (request) => { // Rate limit by username to prevent brute force return request.body.username || request.ip }, onExceeded: (request, key) => { logger.warn('Potential brute force attack', { username: key }) alerting.sendAlert('Brute force attempt: ' + key) } } } }, handler) ``` -------------------------------- ### Custom Hook for Rate Limiting Source: https://github.com/fastify/fastify-rate-limit/blob/main/README.md Integrate rate limiting with custom hooks, such as 'preHandler', after authentication. This example demonstrates setting a userId on the request object before rate limiting is applied. ```javascript await fastify.register(import('@fastify/rate-limit'), { hook: 'preHandler', keyGenerator: function (request) { return request.userId || request.ip } }) fastify.decorateRequest('userId', '') fastify.addHook('preHandler', async function (request) { const { userId } = request.query if (userId) { request.userId = userId } }) ``` -------------------------------- ### Implement Sharded Rate Limiting with Redis Instances Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Configure sharded rate limiting by distributing requests across multiple Redis instances. This example uses a hash function to determine which Redis instance to use for each key, with a limit of 100 requests. ```javascript const redisInstances = [ new Redis({ host: 'redis1.internal' }), new Redis({ host: 'redis2.internal' }), new Redis({ host: 'redis3.internal' }) ] await fastify.register(fastifyRateLimit, { redis: redisInstances[hashKey(key) % 3], max: 100 }) ``` -------------------------------- ### Track Suspicious Activity with Behavioral Analysis Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Monitor for suspicious activity by tracking the number of rate limit approaching events. This example uses a Map to count occurrences and sends an alert if a key exceeds a threshold of 10 approaching events. ```javascript const suspiciousActivity = new Map() await fastify.register(fastifyRateLimit, { onExceeding: (request, key) => { let count = suspiciousActivity.get(key) || 0 suspiciousActivity.set(key, count + 1) // Alert if excessive approaching if (count > 10) { alerting.sendAlert('Suspicious activity: ' + key) } } }) ``` -------------------------------- ### Store Initialization Logic Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/07-lifecycle-and-hooks.md Illustrates how the plugin initializes its storage mechanism, either using a provided store or defaulting to RedisStore or LocalStore. ```javascript // From index.js:110-124 if (settings.store) { pluginComponent.store = new settings.store(globalParams) } else { if (settings.redis) { pluginComponent.store = new RedisStore(...) } else { pluginComponent.store = new LocalStore(...) } } ``` -------------------------------- ### Recommended ioredis Configuration Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Optimal ioredis settings for Fastify Rate Limit performance. ```javascript const redis = new Redis({ host: 'localhost', port: 6379, connectTimeout: 500, // Reduce connection timeout maxRetriesPerRequest: 1 // Limit retries to avoid delays }) ``` -------------------------------- ### Ban Threshold Exceeded Calculation Example Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/05-errors.md Illustrates the calculation to determine if a client has exceeded the ban threshold. ```javascript current_request_count = 120 max = 100 ban = 10 429_responses = 120 - 100 = 20 isBanned = 20 > 10 // true ``` -------------------------------- ### Configuration Reference Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/README.md A detailed breakdown of all configuration options available for the plugin. ```APIDOC ## Configuration Reference This section lists and describes all available configuration options for @fastify/rate-limit. ### Plugin Registration Options **Description**: Covers the 24+ options available when registering the plugin globally using `fastify.register(fastifyRateLimit, options)`. ### Route-Level Overrides **Description**: Explains how to apply specific rate-limiting configurations to individual routes, overriding global settings. ### Dynamic Configuration **Description**: Details how to use asynchronous functions for configuration options, allowing for dynamic adjustments based on request context or external factors. ### Option Values and Defaults **Description**: Provides information on the valid ranges, types, and default values for each configuration option. ### Configuration Patterns **Description**: Illustrates common and recommended patterns for configuring the plugin to achieve desired rate-limiting behaviors. ### Default Values Summary **Description**: A quick reference table summarizing the default values for all configuration options. ``` -------------------------------- ### Custom Error Response Builder Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Example of implementing a custom `errorResponseBuilder` to format the rate limit exceeded response. This allows for tailored error messages and status codes. ```typescript import fastifyRateLimit from '@fastify/rate-limit' await fastify.register(fastifyRateLimit, { errorResponseBuilder: (request, context: errorResponseBuilderContext) => { return { statusCode: context.statusCode, error: context.ban ? 'Banned' : 'Rate Limited', message: `Try again in ${context.after}`, retryAfter: context.ttl } } }) ``` -------------------------------- ### CreateRateLimitOptions Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Options for creating a manual rate limiter with `fastify.createRateLimit()`. This allows for fine-grained control over rate limiting behavior. ```APIDOC ## CreateRateLimitOptions ### Description Options for creating a manual rate limiter with `fastify.createRateLimit()`. ### Fields #### store (FastifyRateLimitStoreCtor) - Optional - Custom store class constructor #### skipOnError (boolean) - Optional - Default: false - Skip rate limiting on store errors #### max (number | function) - Optional - Default: 1000 - Maximum requests or async function returning max #### timeWindow (number | string | function) - Optional - Default: 60000 - Time window (ms), string (e.g., "1 minute"), or async function #### allowList (string[] | function) - Optional - Default: [] - Array of keys to exclude or async function returning boolean #### keyGenerator (function) - Optional - Default: (req) => req.ip - Function to generate unique key #### ban (number) - Optional - Default: -1 - Number of 429 responses before returning 403 (-1 = disabled) ``` -------------------------------- ### RedisStore Constructor Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Initializes a RedisStore instance for distributed rate limiting. Requires an ioredis instance and allows configuration of key prefixes and backoff behaviors. ```javascript function RedisStore(continueExceeding, exponentialBackoff, redis, key) ``` -------------------------------- ### Custom In-Memory Store Implementation Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md A basic in-memory store implementation adhering to the FastifyRateLimitStore interface. ```javascript function CustomStore(options) { this.options = options this.counters = new Map() } CustomStore.prototype.incr = function(key, callback, timeWindow, max) { const now = Date.now() let entry = this.counters.get(key) if (!entry || entry.expiresAt < now) { entry = { current: 0, expiresAt: now + timeWindow } } entry.current++ const ttl = entry.expiresAt - now this.counters.set(key, entry) callback(null, { current: entry.current, ttl }) } CustomStore.prototype.child = function(routeOptions) { return new CustomStore(Object.assign({}, this.options, routeOptions)) } module.exports = CustomStore ``` -------------------------------- ### LocalStore Constructor Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Initializes a LocalStore instance. Use this for single-process applications. Parameters control behavior when limits are exceeded and the cache size. ```javascript function LocalStore(continueExceeding, exponentialBackoff, cache) ``` -------------------------------- ### Fastify Instance Decorations Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/07-lifecycle-and-hooks.md Shows how the plugin decorates the Fastify instance with utility methods and properties for managing rate limiting. ```javascript // From index.js:126-140 fastify.decorateRequest(rateLimitRan, false) // Track if rate limit ran fastify.decorate('createRateLimit', (options) => { // Create a rate limit checker function }) fastify.decorate('rateLimit', (options) => { // Create a hook handler }) ``` -------------------------------- ### Register Main Plugin with Options Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/README.md Register the main fastify-rate-limit plugin with various configuration options. Use this for global rate limiting. ```javascript await fastify.register(fastifyRateLimit, { max: number | function, timeWindow: number | string | function, ban: number, hook: 'onRequest' | 'preHandler' | '...', redis?: RedisClient, keyGenerator?: function, allowList?: string[] | function, store?: StoreClass, errorResponseBuilder?: function, // ... 30+ more options }) ``` -------------------------------- ### Registering a Custom Store Constructor Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Pass the custom store's constructor function (e.g., MyCustomStore) to the `store` option when registering the fastify-rate-limit plugin. Do not pass an instance of the store. ```javascript await fastify.register(fastifyRateLimit, { store: MyCustomStore // Not new MyCustomStore() }) ``` -------------------------------- ### Get Real-Time Rate Limit Status Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Retrieve the current rate limit status for a request. This endpoint allows you to check remaining requests, total limit, reset time, and whether limits have been exceeded or banned. ```javascript fastify.get('/api/rate-limit-status', async (request, reply) => { const limiter = fastify.createRateLimit() const status = await limiter(request) reply.send({ remaining: status.remaining, total: status.max, resetIn: status.ttlInSeconds, exceeded: status.isExceeded, banned: status.isBanned }) }) ``` -------------------------------- ### RedisStore Constructor Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Initializes a new RedisStore instance. This store uses Redis for distributed rate limiting across multiple processes or servers. ```APIDOC ## RedisStore Constructor ### Description Initializes a new RedisStore instance. This store uses Redis for distributed rate limiting across multiple processes or servers. ### Constructor ```javascript function RedisStore(continueExceeding, exponentialBackoff, redis, key) ``` ### Parameters #### Constructor Parameters - **continueExceeding** (boolean) - Optional - Default: `false` - Reset TTL when requests continue after limit exceeded - **exponentialBackoff** (boolean) - Optional - Default: `false` - Apply exponential backoff to TTL when limit exceeded - **redis** (Redis) - Required - ioredis instance connection - **key** (string) - Optional - Default: `'fastify-rate-limit-'` - Key prefix for Redis keys ``` -------------------------------- ### Time Window Configuration (String Format) Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/00-index.md Allows specifying the time window using a human-readable string format (e.g., '1 minute'). ```javascript timeWindow: '1 minute' ``` -------------------------------- ### Applying Rate Limit to Custom Handlers and Routes Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/01-plugin-registration.md Demonstrates how to use the `fastify.rateLimit()` hook to protect a 404 handler and a specific API route. ```javascript import Fastify from 'fastify' import fastifyRateLimit from '@fastify/rate-limit' const fastify = Fastify() await fastify.register(fastifyRateLimit, { global: false, max: 100, timeWindow: '1 minute' }) // Rate limit the 404 handler fastify.setNotFoundHandler({ preHandler: fastify.rateLimit({ max: 5, timeWindow: 60000 }) }, (request, reply) => { reply.code(404).send({ error: 'Not found' }) }) // Rate limit a specific route fastify.get('/api/data', { preHandler: fastify.rateLimit({ max: 50 }) }, (request, reply) => { reply.send({ data: 'content' }) }) ``` -------------------------------- ### Database-Backed Allowlist Check Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Configure rate limiting to check a database table (e.g., 'whitelist') to determine if a client key should be allowed. ```javascript await fastify.register(fastifyRateLimit, { allowList: async (request, key) => { const result = await db.query( 'SELECT is_allowed FROM whitelist WHERE client_id = ?', [key] ) return result.length > 0 } }) ``` -------------------------------- ### Configure Redis for Distributed Rate Limiting Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/04-configuration.md Set up an ioredis client for distributed rate limiting. Recommended to set connection timeouts and retry attempts for stability. ```javascript const Redis = require('ioredis') const redis = new Redis({ host: 'localhost', port: 6379, connectTimeout: 500, // Recommended for rate limiting maxRetriesPerRequest: 1 // Recommended for rate limiting }) await fastify.register(fastifyRateLimit, { redis, max: 100 }) ``` -------------------------------- ### Ban System Configuration (Immediate 403) Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/00-index.md Configures the ban system to immediately return a 403 Forbidden status instead of a 429 Too Many Requests when the limit is exceeded. ```javascript ban: 0 // Immediately return 403 instead of 429 ``` -------------------------------- ### Immediate Ban Configuration Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/05-errors.md Configure the rate limiter to immediately return a 403 Forbidden status instead of a 429 Too Many Requests. ```javascript await fastify.register(fastifyRateLimit, { max: 100, ban: 0 // Immediately 403 instead of 429 }) ``` -------------------------------- ### CreateRateLimitOptions Interface Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Interface for configuring manual rate limiters using `fastify.createRateLimit()`. Customize options like max requests, time window, and key generation. ```typescript interface CreateRateLimitOptions { store?: FastifyRateLimitStoreCtor; skipOnError?: boolean; max?: | number | ((req: FastifyRequest, key: string) => number) | ((req: FastifyRequest, key: string) => Promise); timeWindow?: | number | string | ((req: FastifyRequest, key: string) => number) | ((req: FastifyRequest, key: string) => Promise); allowList?: string[] | ((req: FastifyRequest, key: string) => boolean | Promise); keyGenerator?: (req: FastifyRequest) => string | number | Promise; ban?: number; } ``` -------------------------------- ### Plugin Registration and Decorators Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/README.md This section covers the core plugin registration function and the main decorators available on the Fastify instance for rate limiting. ```APIDOC ## Plugin Registration and Decorators This section details the primary ways to integrate and use the @fastify/rate-limit plugin. ### `fastifyRateLimit()` **Description**: The main function used to register the rate-limiting plugin with your Fastify application. ### `fastify.createRateLimit()` **Description**: Allows for manual creation and checking of rate limits outside of the standard request lifecycle, useful for custom scenarios. ### `fastify.rateLimit()` **Description**: A hook handler function that can be used within Fastify's routing or other hooks to apply rate limiting to specific requests or groups of requests. ### Response Headers Reference **Description**: Details the HTTP headers that the plugin adds to responses, such as `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. ### Error Response Format **Description**: Describes the structure of the response when a rate limit is exceeded, typically a `429 Too Many Requests` error. ### Complete Examples **Description**: Provides practical, end-to-end examples of how to use the plugin in various common scenarios. ``` -------------------------------- ### RateLimitOptions Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Configuration options for route-level rate limiting and the `fastify.rateLimit()` method. This interface extends `CreateRateLimitOptions` and adds specific fields for hook, cache, callbacks, and grouping. ```APIDOC ## RateLimitOptions Complete options for route-level rate limit configuration and `fastify.rateLimit()`. ### Fields Inherits all fields from CreateRateLimitOptions plus: | Field | Type | Default | Description | |---|---|---|---| | hook | RateLimitHook | 'onRequest' | Fastify hook to attach to | | cache | number | 5000 | LRU cache size for in-memory store | | continueExceeding | boolean | false | Reset TTL when requests continue after limit | | onBanReach | function | noop | Callback when ban threshold reached | | groupId | string | — | Group multiple routes for shared limit | | errorResponseBuilder | function | default | Custom error response builder | | enableDraftSpec | boolean | false | Use IETF draft spec headers | | onExceeding | function | noop | Callback each request to limited route | | onExceeded | function | noop | Callback when limit exceeded | | exponentialBackoff | boolean | false | Apply exponential backoff to TTL | ### Callbacks #### onExceeding ```typescript onExceeding?: (req: FastifyRequest, key: string) => void ``` Called each time a request is made while approaching (but not exceeding) the limit. #### onExceeded ```typescript onExceeded?: (req: FastifyRequest, key: string) => void ``` Called when a request exceeds the rate limit. #### onBanReach ```typescript onBanReach?: (req: FastifyRequest, key: string) => void ``` Called when the ban threshold is reached (after `ban` number of 429 responses). ### Usage ```typescript fastify.get('/api', { config: { rateLimit: { max: 100, timeWindow: '1 minute', onExceeding: (req, key) => { console.log(`Approaching limit for ${key}`) }, onExceeded: (req, key) => { console.log(`Rate limited: ${key}`) }, onBanReach: (req, key) => { console.log(`Banned: ${key}`) } } } }, handler) ``` ``` -------------------------------- ### Registering and Using Fastify Rate Limit Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/01-plugin-registration.md This snippet demonstrates how to register the fastify-rate-limit plugin and use its `createRateLimit` function to apply rate limiting to specific routes, including handling rate limit exceeded responses. ```APIDOC ## Registering and Using Fastify Rate Limit ### Description This example shows how to register the fastify-rate-limit plugin globally with custom options and then create specific rate limiters for different routes using `fastify.createRateLimit()`. It also illustrates how to check the rate limit status and respond accordingly when the limit is exceeded. ### Usage 1. Register the plugin with `fastify.register(fastifyRateLimit, { ...options })`. 2. Create a rate limiter instance using `fastify.createRateLimit(customOptions)`. 3. Call the rate limiter instance within your route handler: `await limiter(request)`. 4. Check the returned `RateLimitResult` object (e.g., `isAllowed`, `isExceeded`) to control access. ### Example ```javascript import Fastify from 'fastify' import fastifyRateLimit from '@fastify/rate-limit' const fastify = Fastify() await fastify.register(fastifyRateLimit, { global: false, max: 100, timeWindow: '1 minute' }) // Create a limiter with global options const checkLimit = fastify.createRateLimit() fastify.post('/graphql', async (request, reply) => { const limit = await checkLimit(request) if (!limit.isAllowed && limit.isExceeded) { return reply.code(429).send({ error: 'Rate limit exceeded', retryAfter: limit.ttlInSeconds }) } // Process GraphQL query return reply.send({ data: 'result' }) }) // Create a limiter with custom options const strictLimit = fastify.createRateLimit({ max: 10, timeWindow: 60000 }) fastify.post('/login', async (request, reply) => { const limit = await strictLimit(request) if (limit.isExceeded) { return reply.code(429).send('Too many login attempts') } // Process login return reply.send({ token: 'xxx' }) }) ``` ``` -------------------------------- ### Using fastify.rateLimit as a Hook Handler Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/01-plugin-registration.md This snippet demonstrates how to use `fastify.rateLimit()` as a `preHandler` hook to apply rate limiting to specific routes or handlers, such as the 404 handler. ```APIDOC ## Using fastify.rateLimit as a Hook Handler ### Description This example shows how to use the `fastify.rateLimit()` function, which returns a pre-handler hook, to apply rate limiting to specific routes or even the 404 handler. This provides fine-grained control over which parts of your application are rate-limited and with what specific configurations. ### Usage 1. Register the plugin with `fastify.register(fastifyRateLimit, { ...options })`. 2. Obtain the rate limit hook using `fastify.rateLimit(options)`. 3. Apply the returned hook to a route's `preHandler` option or use it in `fastify.setNotFoundHandler()`. ### Example ```javascript import Fastify from 'fastify' import fastifyRateLimit from '@fastify/rate-limit' const fastify = Fastify() await fastify.register(fastifyRateLimit, { global: false, max: 100, timeWindow: '1 minute' }) // Rate limit the 404 handler fastify.setNotFoundHandler({ preHandler: fastify.rateLimit({ max: 5, timeWindow: 60000 }) }, (request, reply) => { reply.code(404).send({ error: 'Not found' }) }) // Rate limit a specific route fastify.get('/api/data', { preHandler: fastify.rateLimit({ max: 50 }) }, (request, reply) => { reply.send({ data: 'content' }) }) ``` ``` -------------------------------- ### Storage Implementations Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/README.md Details the different storage mechanisms available for rate limiting, including in-memory and distributed options. ```APIDOC ## Storage Implementations This section describes the available storage backends for managing rate limit counts and states. ### `LocalStore` **Description**: An in-memory Least Recently Used (LRU) cache implementation for storing rate limit data. Suitable for single-node applications. ### `RedisStore` **Description**: A distributed storage implementation that uses Redis to store rate limit data. Ideal for multi-instance or clustered applications. ### Custom Store Interface **Description**: Defines the interface and methods required for implementing a custom storage solution compatible with the @fastify/rate-limit plugin. ### Store Methods and Lifecycle **Description**: Explains the lifecycle of store instances and the contract for methods like `increment`, `get`, `set`, and `delete`. ### Lua Script Reference **Description**: Details the Lua scripts used by the `RedisStore` for atomic operations on Redis. ### Implementation Examples **Description**: Provides examples of how to configure and use different storage implementations, including custom ones. ``` -------------------------------- ### Default Plugin Parameters Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/07-lifecycle-and-hooks.md Overview of the default global parameters applied by the rate limit plugin if not explicitly provided. ```javascript // From index.js:37-108 globalParams = { global: true, // Default max: 1000, // Default timeWindow: 60000, // Default ban: -1, // Default hook: 'onRequest', // Default enableDraftSpec: false, // Default // ... and many more } ``` -------------------------------- ### Register Fastify Rate Limit Plugin with Options Source: https://github.com/fastify/fastify-rate-limit/blob/main/README.md Register the rate limiting plugin with custom options. Configure global application of limits, maximum requests, ban thresholds, time window, hook, cache size, IP allow list, Redis connection, namespace, continuation of exceeding limits, skipping errors, custom key generation, and response building. ```javascript await fastify.register(import('@fastify/rate-limit'), { global : false, // default true max: 3, // default 1000 ban: 2, // default -1 timeWindow: 5000, // default 1000 * 60 hook: 'preHandler', // default 'onRequest' cache: 10000, // default 5000 allowList: ['127.0.0.1'], // default [] redis: new Redis({ host: '127.0.0.1' }), // default null nameSpace: 'teste-ratelimit-', // default is 'fastify-rate-limit-' continueExceeding: true, // default false skipOnError: true, // default false keyGenerator: function (request) { /* ... */ }, // default (request) => request.ip errorResponseBuilder: function (request, context) { /* ... */}, enableDraftSpec: true, // default false. Uses IEFT draft header standard addHeadersOnExceeding: { // default show all the response headers when rate limit is not reached 'x-ratelimit-limit': true, 'x-ratelimit-remaining': true, 'x-ratelimit-reset': true }, addHeaders: { // default show all the response headers when rate limit is reached 'x-ratelimit-limit': true, 'x-ratelimit-remaining': true, 'x-ratelimit-reset': true, 'retry-after': true } }) ``` -------------------------------- ### Allowlist Configuration (Function) Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/00-index.md Dynamically determines if a client should be allowed based on request properties, such as user plan. ```javascript allowList: (request, key) => request.user?.plan === 'premium' ``` -------------------------------- ### Set Up Cross-Region Rate Limiting with Global Redis Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/06-advanced-usage.md Implement cross-region rate limiting by using a central, globally accessible Redis instance. This configuration applies a limit of 1000 requests per hour, namespaced under 'global-', to ensure consistent limits across different regions. ```javascript const redisGlobal = new Redis({ host: 'global-redis.region-central.internal' }) await fastify.register(fastifyRateLimit, { redis: redisGlobal, nameSpace: 'global-', max: 1000, timeWindow: '1 hour' }) ``` -------------------------------- ### Scenario 1: Redis Outage Handling Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/05-errors.md Configures rate limiting to skip errors from the Redis store during an outage and sets up error monitoring for the Redis connection. ```javascript const redis = new Redis({ connectTimeout: 500, maxRetriesPerRequest: 1 }) await fastify.register(fastifyRateLimit, { redis, skipOnError: true }) redis.on('error', (err) => { logger.error('Redis rate limit store error:', err) alerting.sendAlert('Rate limit store down') }) ``` -------------------------------- ### Create and Use Manual Rate Limiter Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/README.md Create a rate limiter instance for manual checks within your request handlers. This allows for custom rate limiting logic. ```javascript const limiter = fastify.createRateLimit({ max: 100 }) const result = await limiter(request) // result.isAllowed | result.isExceeded | result.remaining ``` -------------------------------- ### Time Window Configuration (Milliseconds) Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/00-index.md Configures the time window for rate limiting in milliseconds. ```javascript timeWindow: 60000 ``` -------------------------------- ### Registering Rate Limiter with onBanReach Callback Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/05-errors.md Configure the rate limiter to execute an `onBanReach` callback when a client is banned. ```javascript await fastify.register(fastifyRateLimit, { max: 100, ban: 10, onBanReach: (request, key) => { console.log(`Client ${key} banned`) // Log to security system // Block IP in firewall // Add to database blacklist } }) ``` -------------------------------- ### Allowlist Configuration (Array) Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/00-index.md Specifies an array of client keys (e.g., IP addresses) that should be excluded from rate limiting. ```javascript allowList: ['127.0.0.1', 'internal-api'] ``` -------------------------------- ### RedisStore Child Store Initialization Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/07-lifecycle-and-hooks.md A RedisStore creates a new instance with a prefixed key derived from the parent store's key and route information. ```javascript RedisStore.prototype.child = function(routeOptions) { return new RedisStore( routeOptions.continueExceeding, routeOptions.exponentialBackoff, this.redis, `${this.key}${routeOptions.routeInfo.method}${routeOptions.routeInfo.url}-` ) } ``` -------------------------------- ### Enable Draft Spec Headers Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/04-configuration.md Use IETF draft specification headers instead of the de-facto standard headers for rate limiting information. ```javascript await fastify.register(fastifyRateLimit, { enableDraftSpec: true, max: 100 }) ``` -------------------------------- ### RateLimitPluginOptions Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Configuration options for registering the rate limit plugin globally with `fastify.register()`. This interface extends `RateLimitOptions` and adds fields for global application, Redis integration, and header customization. ```APIDOC ## RateLimitPluginOptions Complete options for plugin registration via `fastify.register()`. ### Fields Inherits all fields from RateLimitOptions plus: | Field | Type | Default | Description | |---|---|---|---| | global | boolean | true | Apply to all routes in scope | | cache | number | 5000 | LRU cache size | | redis | Redis | null | ioredis instance for distributed limiting | | nameSpace | string | 'fastify-rate-limit-' | Redis key prefix | | addHeaders | object | all true | Headers to add when limit exceeded | | addHeadersOnExceeding | object | all true | Headers to add when approaching limit | ### Usage ```typescript await fastify.register(fastifyRateLimit, { global: true, max: 1000, timeWindow: '1 minute', redis: redisClient, nameSpace: 'myapp-', enableDraftSpec: false, addHeaders: { 'x-ratelimit-limit': true, 'x-ratelimit-remaining': true, 'x-ratelimit-reset': true, 'retry-after': true } }) ``` ``` -------------------------------- ### Basic Global Rate Limit Configuration Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/00-index.md Applies a basic global rate limit to all requests using the plugin. ```javascript await fastify.register(fastifyRateLimit, { max: 100, timeWindow: '1 minute' }) ``` -------------------------------- ### LocalStore Constructor Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/02-stores.md Initializes a new LocalStore instance. This store is an in-memory LRU cache suitable for single-process applications. ```APIDOC ## LocalStore Constructor ### Description Initializes a new LocalStore instance. This store is an in-memory LRU cache suitable for single-process applications. ### Constructor ```javascript function LocalStore(continueExceeding, exponentialBackoff, cache) ``` ### Parameters #### Constructor Parameters - **continueExceeding** (boolean) - Optional - Default: `false` - Reset TTL when requests continue after limit exceeded - **exponentialBackoff** (boolean) - Optional - Default: `false` - Apply exponential backoff to TTL when limit exceeded - **cache** (number) - Optional - Default: `5000` - Maximum number of entries in LRU cache ``` -------------------------------- ### RateLimitOptions Interface Source: https://github.com/fastify/fastify-rate-limit/blob/main/_autodocs/03-types.md Defines the complete options for route-level rate limit configuration and `fastify.rateLimit()`. ```typescript interface RateLimitOptions extends CreateRateLimitOptions { hook?: RateLimitHook; cache?: number; continueExceeding?: boolean; onBanReach?: (req: FastifyRequest, key: string) => void; groupId?: string; errorResponseBuilder?: ( req: FastifyRequest, context: errorResponseBuilderContext ) => object; enableDraftSpec?: boolean; onExceeding?: (req: FastifyRequest, key: string) => void; onExceeded?: (req: FastifyRequest, key: string) => void; exponentialBackoff?: boolean; } ```