Advanced Middleware PatternsLesson 5.1
How to build a rate limiting middleware from scratch
rate limiting concept, in-memory request tracking, IP-based limits, window reset, 429 Too Many Requests, Retry-After header, sliding vs fixed window, express-rate-limit library
Rate Limiting Middleware
Rate limiting prevents API abuse by capping how many requests a client can make in a time window. Every production API needs it.
In-memory rate limiter
const requestCounts = new Map(); // IP -> { count, resetTime }
function rateLimiter(maxRequests = 100, windowMs = 60 * 1000) {
return (req, res, next) => {
const ip = req.ip;
const now = Date.now();
const record = requestCounts.get(ip);
if (!record || now > record.resetTime) {
requestCounts.set(ip, { count: 1, resetTime: now + windowMs });
return next();
}
if (record.count >= maxRequests) {
const retryAfter = Math.ceil((record.resetTime - now) / 1000);
res.set('Retry-After', retryAfter);
return res.status(429).json({
error: 'Too many requests',
retryAfter
});
}
record.count++;
next();
};
}
app.use(rateLimiter(100, 60000)); // 100 req/min
app.use('/auth', rateLimiter(5, 60000)); // stricter on auth routesFor production, use the express-rate-limit package with a Redis store โ in-memory counters reset on server restart and don't work across multiple processes. The built-in version here is for single-process development.
