hono-redis-kappe
A flexible and extensible rate limiting middleware for Hono, powered by Redis. This package helps you protect your Hono applications from abuse and ensures fair resource usage by limiting the number of requests a client can make within a specified time window.
Features
- Redis-backed: Leverages Redis for efficient and distributed rate limiting across multiple instances.
- Highly Customizable: Provides interfaces and classes to customize key generation, error responses, and header management.
- Immutable Configuration: Uses immutable patterns for robust and predictable configuration management.
Installation
npm install hono-redis-kappe ioredis
Usage
Basic Usage
The simplest way to use the rate limiter is with its default settings, which limit requests based on the client's IP address.
import { Hono } from "hono";
import { Redis } from "ioredis";
import { RateLimiterFactory } from "hono-redis-kappe";
const app = new Hono();
const redis = new Redis();
app.use(
"*",
RateLimiterFactory.create({
redis,
requestLimit: 100,
timeWindowSeconds: 60,
}),
);
app.get("/", (c) => {
return c.text("Hello Hono!");
});
export default app;
Customizing Key Generation
You can define how the rate limit key is generated by implementing the IKeyGenerator
interface or by using the FunctionBasedKeyGenerator
.
IP-Based (Default)
The default IpBasedKeyGenerator
attempts to get the client's IP from x-forwarded-for
, cf.ip
(Cloudflare), or x-real-ip
headers.
import { RateLimiterFactory, IpBasedKeyGenerator } from "hono-redis-kappe";
const rateLimiter = RateLimiterFactory.create({
redis: redis,
keyGenerator: new IpBasedKeyGenerator(),
});
Custom Function-Based Key Generation
You can provide a function to generate the key based on your specific needs, for example, by user ID from a session or JWT.
import { RateLimiterFactory, FunctionBasedKeyGenerator } from "hono-redis-kappe";
const rateLimiter = RateLimiterFactory.create({
redis: redis,
keyGenerator: new FunctionBasedKeyGenerator((c) => {
const userId = c.get("jwtPayload")?.sub;
return userId || c.req.header("x-forwarded-for") || "anonymous";
}),
});
Handling Rate Limit Errors
By default, an HTTPException with status 429 (Too Many Requests) is thrown. You can customize this behavior.
import { RateLimiterFactory, DefaultErrorResponseHandler } from "hono-redis-kappe";
const rateLimiter = RateLimiterFactory.create({
redis: redis,
errorResponseHandler: new DefaultErrorResponseHandler(),
});
JSON Error Response
You can return a JSON response with or without detailed information.
import { RateLimiterFactory, JsonErrorResponseHandler } from "hono-redis-kappe";
const rateLimiterJsonDetailed = RateLimiterFactory.create({
redis: redis,
errorResponseHandler: new JsonErrorResponseHandler(true), // with details (default)
});
const rateLimiterJsonSimple = RateLimiterFactory.create({
redis: redis,
errorResponseHandler: new JsonErrorResponseHandler(false), // without details
});
Reusable Factory for Multiple Configurations
If you have multiple endpoints requiring different rate limit configurations, you can create a reusable factory.
import { Hono } from "hono";
import { Redis } from "ioredis";
import { RateLimiterFactory } from "hono-redis-kappe";
const app = new Hono().basePath("/api");
const redis = new Redis();
const rateLimiter = RateLimiterFactory.createReusableFactory({
redis: redis,
keyPrefix: "rate_limit",
});
app.get(
"/public",
rateLimiter({
requestLimit: 150,
timeWindowSeconds: 60,
}),
(c) => c.text("This is a public endpoint."),
);
app.get(
"/private",
rateLimiter({
requestLimit: 50,
timeWindowSeconds: 60,
// tip: you could also override the keyGenerator here for user-specific limits
}),
(c) => c.text("This is a private endpoint."),
);
app.get(
"/constrained",
rateLimiter({
requestLimit: 1,
timeWindowSeconds: 300,
}),
(c) => c.text("This is a constrained endpoint."),
);
export default app;
License
This project is licensed under the MIT License.