api-rate-shield
v1.0.0
Published
A smart, flexible API rate limiter for Express/Fastify with sliding window algorithm, in-memory store, and optional Redis support.
Maintainers
Readme
api-rate-shield
A smart, flexible API rate limiter for Express and Fastify using the sliding window algorithm. Ships with an efficient in-memory store (zero dependencies) and an optional Redis store adapter for distributed/scalable deployments.
Features
- 🪟 Sliding Window Algorithm — more accurate than fixed-window counters; prevents burst abuse at window boundaries.
- 🧠 In-Memory Store — zero-dependency, self-cleaning store built in. Perfect for single-process apps.
- 🔴 Redis Store (Optional) — drop-in Redis adapter using sorted sets for multi-process / distributed environments.
- 🔑 Flexible Key Strategies — rate limit by IP address, user ID, API key, or any custom identifier.
- 🛡️ Block Duration — optionally block abusers for an extended period after exceeding the limit.
- ✅ Whitelist — exempt specific IPs, users, or API keys from rate limiting.
- 🎯 Skip Function — programmatically skip rate limiting for specific requests (e.g., health checks).
- 📊 Standard Headers — sends
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset, andRetry-Afterheaders. - 🪝 Callback Hook —
onLimitReachedcallback fires when a client exceeds the limit. - 🧹 Auto Cleanup — memory store automatically prunes expired entries.
Installation
npm install api-rate-shieldQuick Start
const express = require('express');
const { rateLimit } = require('api-rate-shield');
const app = express();
// Apply rate limiting: 100 requests per minute per IP
app.use(rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 100 // max 100 requests per window
}));
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello!' });
});
app.listen(3000);Advanced Usage
Custom Key Strategy
// Rate limit by authenticated user ID
app.use('/api', rateLimit({
windowMs: 60000,
max: 50,
keyBy: 'userId' // extracts from req.user.id
}));
// Rate limit by API key header
app.use('/api', rateLimit({
windowMs: 60000,
max: 200,
keyBy: 'apiKey' // extracts from X-Api-Key header
}));
// Custom key extraction
app.use('/api', rateLimit({
windowMs: 60000,
max: 30,
keyBy: (req) => req.headers['x-tenant-id'] || req.ip
}));Block Duration (Penalty)
// Block abusers for 5 minutes after exceeding limit
app.use(rateLimit({
windowMs: 60000,
max: 20,
blockDuration: 5 * 60 * 1000 // 5 min block
}));Whitelist & Skip
app.use(rateLimit({
windowMs: 60000,
max: 50,
whitelist: ['127.0.0.1', '::1'], // never rate-limit localhost
skip: (req) => req.path === '/health' // skip health check endpoint
}));Callback on Limit Reached
app.use(rateLimit({
windowMs: 60000,
max: 100,
onLimitReached: (req, res, info) => {
console.warn(`Rate limit exceeded by ${info.key}`);
}
}));Redis Store (Distributed)
const Redis = require('ioredis');
const { rateLimit, RedisStore } = require('api-rate-shield');
const redis = new Redis();
app.use(rateLimit({
windowMs: 60000,
max: 100,
store: new RedisStore(redis, 'myApp:rateLimit:')
}));Programmatic Reset
const limiter = rateLimit({ windowMs: 60000, max: 10 });
app.use(limiter);
// Reset a specific user's limits
limiter.reset('192.168.1.1');
// Clear all limits
limiter.clear();Options
| Option | Type | Default | Description |
|---|---|---|---|
| windowMs | number | 60000 | Sliding window duration in milliseconds. |
| max | number | 100 | Maximum number of requests allowed in the window. |
| keyBy | string \| Function | 'ip' | Key strategy: 'ip', 'userId', 'apiKey', or custom (req) => string. |
| store | Object | MemoryStore | Store instance (MemoryStore or RedisStore). |
| headers | boolean | true | Send X-RateLimit-* response headers. |
| blockDuration | number | 0 | Extra block time in ms after limit exceeded. 0 = no extra block. |
| message | string | 'Too many requests...' | Error message in the 429 response body. |
| statusCode | number | 429 | HTTP status code for rate-limited responses. |
| onLimitReached | Function | null | Callback (req, res, info) => void fired on limit exceeded. |
| skip | Function | null | (req) => boolean — return true to bypass rate limiting. |
| whitelist | Array<string> | [] | Keys (IPs, user IDs) that are always allowed. |
Response Headers
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed in the window. |
| X-RateLimit-Remaining | Remaining requests in the current window. |
| X-RateLimit-Reset | Unix timestamp (seconds) when the window resets. |
| Retry-After | Seconds to wait before retrying (on 429 responses). |
License
MIT
