Express Rate Limit Redis Store

Apply distributed rate limiting in Express with express-rate-limit backed by a Redis store, keying by user identity and API token.

TypescriptNodeResilience

Code

snippet
import express from 'express';
import rateLimit from 'express-rate-limit';
import { RedisStore } from 'rate-limit-redis';
import { createClient } from 'redis';

const redis = createClient({ url: process.env.REDIS_URL ?? 'redis://127.0.0.1:6379' });
await redis.connect();

const limiter = rateLimit({
  store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
  windowMs: 60_000,
  limit: 120,
  keyGenerator: (req) => {
    const apiKey = req.header('x-api-key');
    const subject = apiKey ?? req.header('x-user-id') ?? req.ip;
    return subject + ':' + (apiKey ? 'key' : 'user');
  },
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  skip: (req) => req.path === '/healthz',
  handler: (req, res) => {
    res.status(429).json({ error: 'rate limit exceeded', retryAfter: res.getHeader('Retry-After') });
  },
});

const app = express();
app.use('/api/', limiter);

app.get('/api/report', (req, res) => res.json({ ok: true }));
app.get('/healthz', (req, res) => res.json({ status: 'up' }));

app.listen(3000);