JAVASCRIPT

Implement API Rate Limiting with Redis and Express

Protect your Node.js Express API from abuse and brute-force attacks by implementing effective rate limiting using Redis for tracking request counts.

const express = require('express');
const redis = require('redis');

const app = express();
const PORT = 3000;

// Connect to Redis globally and reuse the client
const redisClient = redis.createClient({ url: 'redis://localhost:6379' }); // Use URL for connection

redisClient.on('connect', () => console.log('Connected to Redis!'));
redisClient.on('error', (err) => console.log('Redis Client Error', err));

async function connectRedis() {
  if (!redisClient.isOpen) {
    await redisClient.connect();
  }
}

connectRedis(); // Connect on server startup

const RATE_LIMIT_WINDOW_SECONDS = 60; // 1 minute
const MAX_REQUESTS_PER_WINDOW = 5; // 5 requests

async function rateLimiter(req, res, next) {
  const ip = req.ip; // Or req.headers['x-forwarded-for'] for proxied requests
  const key = `rate_limit:${ip}`;

  try {
    // Use the already connected redisClient
    const requests = await redisClient.incr(key);

    if (requests === 1) {
      // Set expiry only for the first request in the window
      await redisClient.expire(key, RATE_LIMIT_WINDOW_SECONDS);
    }

    if (requests > MAX_REQUESTS_PER_WINDOW) {
      return res.status(429).json({ message: 'Too many requests, please try again later.' });
    }
    next();
  } catch (error) {
    console.error('Rate Limiter Error:', error);
    next(error); // Pass error to Express error handler
  }
}

app.use(express.json());
app.use(rateLimiter); // Apply rate limiting to all routes

app.get('/api/data', (req, res) => {
  res.json({ message: 'This is some protected data.' });
});

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});
How it works: This Node.js Express snippet demonstrates API rate limiting using Redis. It assigns a unique key (typically based on the client's IP address) for each client and tracks the number of requests within a defined time window. Redis's `incr` and `expire` commands are used efficiently to count requests and automatically reset the count. If a client exceeds the `MAX_REQUESTS_PER_WINDOW` limit, subsequent requests are blocked with a `429 Too Many Requests` status, protecting the API from brute-force attacks, denial-of-service attempts, and resource exhaustion.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs