An in-memory rate limiter middleware to protect APIs from abuse.
import type { Request, Response, NextFunction } from class=class="text-emerald-400">"text-emerald-400">'express'
interface RateLimitEntry {
count: number
resetAt: number
}
function createRateLimiter(options: { windowMs: number; max: number }) {
const { windowMs, max } = options
const store = new Map<string, RateLimitEntry>()
class=class="text-emerald-400">"text-gray">// Cleanup expired entries every minute
setInterval(() => {
const now = Date.now()
for (const [key, entry] of store) {
if (entry.resetAt < now) store.delete(key)
}
}, 60_000)
return (req: Request, res: Response, next: NextFunction) => {
const key = req.ip || class=class="text-emerald-400">"text-emerald-400">'unknown'
const now = Date.now()
const entry = store.get(key)
if (!entry || entry.resetAt < now) {
store.set(key, { count: 1, resetAt: now + windowMs })
return next()
}
if (entry.count >= max) {
res.set(class=class="text-emerald-400">"text-emerald-400">'Retry-After', String(Math.ceil((entry.resetAt - now) / 1000)))
return res.status(429).json({ error: class=class="text-emerald-400">"text-emerald-400">'Too many requests' })
}
entry.count++
next()
}
}
export const apiLimiter = createRateLimiter({ windowMs: 60_000, max: 100 })Apply to routes: app.use('/api', apiLimiter). It allows 100 requests per minute per IP. For production, replace the Map store with Redis for multi-instance support.
Let's discuss how we can bring your idea to life. From initial concept to production-ready product — we've got you covered.