hono-rate-limiter
repository·main·Indexed 20 days ago
https://github.com/rhinobase/hono-rate-limiterA lightweight rate limiting middleware for the Hono web framework designed to protect APIs from abuse. It supports multiple storage backends including MemoryStore, RedisStore, and UnstorageStore, and provides native integration for Cloudflare rate-limiting bindings. The library includes utilities for setting rate limit headers following IETF Draft 6 and Draft 7 specifications, as well as a specialized webSocketLimiter for WebSocket connections.
What's inside hono-rate-limiter
- Hono Rate Limiter is a simple rate limiting middleware designed for the Hono web framework. It allows you to restrict the number of requests a user or IP can make to your API within a specific timeframe to prevent abuse and ensure service stability.
Configure webSocketLimiter options
mainThe
webSocketLimiteraccepts aWSConfigPropsobject to customize rate-limiting behavior.Option Type Default Description limitnumber | ((c: Context) => Promise<number>)5The maximum number of allowed hits. Can be a static number or a function returning a limit based on context. windowMsnumber60_000The time window in milliseconds for the rate limit. messagestring'Too many requests...'The message sent when the limit is exceeded. statusCodenumber1008The WebSocket close code used when the limit is exceeded. keyGenerator(c: Context) => Promise<string>Required A function to generate a unique identifier (key) for the client (e.g., from IP or headers). skip(event: any, ws: any) => Promise<boolean>() => falseA function to determine if a specific message should be ignored by the rate limiter. handler(event: any, ws: any, options: any) => Promise<void>async (_, ws, opts) => ws.close(opts.statusCode, opts.message)The function called when the limit is exceeded. storeStorenew MemoryStore()The storage engine used to track hits (e.g., MemoryStore).requestPropertyNamestring'rateLimit'The key used to store RateLimitInfoin the Hono context.requestStorePropertyNamestring'rateLimitStore'The key used to store the store's interface ( getKey,resetKey) in the Hono context.skipFailedRequestsbooleanfalseIf true, failed message processing will decrement the hit counter.skipSuccessfulRequestsbooleanfalseIf true, successful message processing will decrement the hit counter.Configure the Redis store options
mainWhen using the Redis store, you must provide an
Optionsobject. The configuration includes the Redis client, an optional key prefix, and an expiry reset setting.client: An object implementing theRedisClientinterface (required).prefix: A string prepended to all keys stored in Redis (optional).resetExpiryOnChange: A boolean that determines whether the key's expiry is reset every time the hit count changes (optional).
const options: Options = { client: myRedisClient, prefix: 'rate-limit:', resetExpiryOnChange: true };Configure Cloudflare rateLimiter via binding
mainIf you are deploying to Cloudflare and want to use Cloudflare's native rate-limiting capabilities, provide a
bindingin the configuration. TherateLimiterfunction will detect this and switch tocloudflareRateLimitermode.Cloudflare Configuration Options:
binding: The Cloudflare rate-limiting binding. This can be the binding object itself or a function(c) => bindingthat retrieves it from the context.keyGenerator: A function to generate the key used by Cloudflare's engine.skip: A function to skip rate limiting for certain requests.handler: Custom logic to execute when the limit is exceeded.message: The response message/object when limited.statusCode: The HTTP status code returned when limited.
// Example using a Cloudflare binding app.use( '/', rateLimiter({ binding: 'MY_RATE_LIMIT_BINDING', // or a function to get it keyGenerator: (c) => c.req.header('x-real-ip'), }) );Configure UnstorageStore options
mainWhen instantiating
UnstorageStore, you can provide the following configuration options in the constructor:Option Type Description storageUnstorageInstanceRequired. An object containing get,set, andremovemethods.prefixstringOptional. A string prepended to all keys in the storage. Defaults to hrl:const store = new UnstorageStore({ storage: myStorage, prefix: 'custom-prefix:' });Configure Hono rateLimiter options
mainWhen using the standard Hono implementation, you can pass a
ConfigPropsobject torateLimiterto customize behavior:Option Type Default Description windowMsnumber60_000The duration of the rate-limiting window in milliseconds. limitnumberor(c: Context) => number5The maximum number of hits allowed within the window. Can be a function for dynamic limits. messagestringor(c: Context) => string | object'Too many requests...'The response message or JSON object when the limit is exceeded. statusCodenumber429The HTTP status code returned when rate-limited. standardHeaders'draft-6' | 'draft-7' | booleanWhether to include RateLimit-*headers. Defaults to'draft-6'.requestPropertyNamestring'rateLimit'The key used to store RateLimitInfoin the Hono context viac.get().requestStorePropertyNamestring'rateLimitStore'The key used to store the store's interface in the Hono context via c.get().skip(c: Context) => boolean() => falseA function that returns trueto skip rate limiting for a specific request.keyGenerator(c: Context) => stringRequired A function that generates a unique identifier (key) for the client (e.g., IP address). skipFailedRequestsbooleanfalseIf true, failed requests (based onrequestWasSuccessful) will not count towards the limit.skipSuccessfulRequestsbooleanfalseIf true, successful requests will not count towards the limit.requestWasSuccessful(c: Context) => boolean(c) => c.res.status < 400Determines if a request is considered successful for the purpose of skipFailedRequests/skipSuccessfulRequests.handler(c, next, options) => Promise<Response>Default handler Custom logic to execute when the rate limit is exceeded. storeStorenew MemoryStore()The storage engine used to track hits. Configure RedisStore options
mainWhen instantiating
RedisStore, you can provide the following options:Option Type Default Description clientRedisClientRequired An instance of a Redis client. prefixstring'hrl:'A string prepended to all keys stored in Redis to avoid collisions. resetExpiryOnChangebooleanfalseIf true, the key's expiry is reset every time the hit count changes (sliding window behavior). Iffalse, the expiry is set once when the key is first created (fixed window behavior).const store = new RedisStore({ client: redisClient, prefix: 'custom-prefix:', resetExpiryOnChange: true });Configure Hono Rate Limiter middleware
mainWhen using the standard Hono rate limiter, you can provide a
HonoConfigTypeobject. Key configuration options include:windowMs: Duration (in ms) to track requests. Defaults to60000(1 minute).limit: Maximum connections allowed in the window. Can be anumberor a function(c) => Promisify<number>.standardHeaders: Enables standardized rate limit headers. Supportstrue,false, `
Use UnstorageStore for rate limiting with Unstorage
mainThe
UnstorageStoreclass allows you to use Unstorage as the backend forhono-rate-limiter. This is useful if you want to persist rate limit data across different storage engines (like Redis, Cloudflare KV, or memory) using the Unstorage API.To use it, you must provide an object that implements the
UnstorageInstanceinterface, which requiresget,set, andremovemethods.import { UnstorageStore, type UnstorageInstance } from 'hono-rate-limiter'; // 1. Define your Unstorage-compatible instance const myStorage: UnstorageInstance = { get: async (key) => { /* implementation */ }, set: async (key, value) => { /* implementation */ }, remove: async (key) => { /* implementation */ }, }; // 2. Initialize the store const store = new UnstorageStore({ storage: myStorage, prefix: 'my-app-rl:', // Optional: defaults to 'hrl:' });RedisStore public API methods
mainThe
RedisStoreclass provides the following methods for managing rate limit state:init(options: RateLimitConfiguration<E, P, I>): void: Initializes the store with the rate limiter's configuration (e.g., settingwindowMs).get(key: string): Promise<ClientRateLimitInfo | undefined>: Fetches the current hit count andresetTimefor a specific key.increment(key: string): Promise<ClientRateLimitInfo>: Atomically increments the hit count for a key and returns the updatedClientRateLimitInfo.decrement(key: string): Promise<void>: Decrements the hit count for a key using the RedisDECRcommand.resetKey(key: string): Promise<void>: Deletes the key from Redis, effectively resetting the rate limit for that identifier.
Set the Retry-After header
mainUse
setRetryAfterHeaderto set the standardRetry-Afterheader on a Hono response. This informs the client how many seconds to wait before retrying the request.The header value is calculated based on the
resetTimeprovided in theRateLimitInfoobject or thewindowMsduration.import { setRetryAfterHeader } from "hono-rate-limiter"; // Inside a Hono handler: setRetryAfterHeader(context, info, windowMs);Access rate limiter stores and types
mainThe package exports all available storage implementations (e.g., memory, Redis) via thestoresmodule and all necessary configuration and response types via thetypesmodule.