Implementing Rate Limiting in Node.js with Express and TypeScript

Muke Johnbaptist

Muke Johnbaptist

August 26, 2024

Implementing Rate Limiting in Node.js with Express and TypeScript

Introduction

Rate limiting is an essential strategy for protecting web applications and APIs from abuse, such as denial-of-service (DoS) attacks, brute-force attacks, and excessive usage. By controlling the number of requests a user can make to your server, you can ensure fair usage and maintain the stability of your application.

In this blog, we'll explore how to implement rate limiting in a Node.js application using Express and TypeScript. We'll dive into two libraries that are particularly effective for this purpose:

  1. express-rate-limit: To block requests that exceed specified limits.
  2. express-slow-down: To slow down similar requests coming from the same actor.

Let's get started!

Setting Up Your Node.js and Express Application

Before we implement rate limiting, let's set up a basic Node.js and Express application with TypeScript.

  1. Initialize a new Node.js project:
mkdir rate-limiting-app
cd rate-limiting-app
npm init -y
  1. Install required dependencies:
npm install express express-rate-limit express-slow-down
npm install typescript @types/node @types/express ts-node --save-dev
  1. Set up TypeScript configuration:
  2. Create a tsconfig.json file in the root of your project:
{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}
  1. Create the basic Express server:
  2. Inside a new src folder, create an index.ts file:
import express, { Request, Response } from 'express';

const app = express();

app.get('/', (req: Request, res: Response) => {
  res.send('Welcome to the Rate Limiting Demo!');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
  1. Run the application:
npx ts-node src/index.ts

Now that we have our basic Express server set up, let's implement rate limiting.

Using express-rate-limit to Block Excessive Requests

express-rate-limit is a simple yet powerful library that allows you to block excessive requests from a single IP address.

  1. Install express-rate-limit (if not already installed):
npm install express-rate-limit
  1. Configure and apply the rate limiter:
  2. Update your index.ts file to include the rate limiter:
import express, { Request, Response } from 'express';
import rateLimit from 'express-rate-limit';

const app = express();

// Configure rate limiter
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
  message: 'Too many requests from this IP, please try again later.',
});

// Apply the rate limiter to all requests
app.use(limiter);

app.get('/', (req: Request, res: Response) => {
  res.send('Welcome to the Rate Limiting Demo!');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

With this configuration, a user can make up to 100 requests every 15 minutes from a single IP address. If they exceed this limit, they’ll receive an error message.

Using express-slow-down to Throttle Requests

While blocking requests is effective, sometimes you may prefer to slow down the requests instead of blocking them outright. This is where express-slow-down comes into play.

  1. Install express-slow-down:
npm install express-slow-down
  1. Configure and apply the slow-down middleware:
  2. Update your index.ts file to include the slow-down middleware:
import express, { Request, Response } from 'express';
import rateLimit from 'express-rate-limit';
import slowDown from 'express-slow-down';

const app = express();

// Configure rate limiter
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
  message: 'Too many requests from this IP, please try again later.',
});

// Configure slow down middleware
const speedLimiter = slowDown({
  windowMs: 15 * 60 * 1000, // 15 minutes
  delayAfter: 50, // Allow 50 requests per 15 minutes, then...
  delayMs: 500, // Begin adding 500ms of delay per request above 50
});

// Apply the rate limiter to all requests
app.use(limiter);
app.use(speedLimiter);

app.get('/', (req: Request, res: Response) => {
  res.send('Welcome to the Rate Limiting Demo!');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

In this setup, the server allows up to 50 requests within 15 minutes without any delays. After that, it introduces a delay of 500ms for each additional request. This approach helps prevent server overload while still allowing some level of access.

Conclusion

By integrating express-rate-limit and express-slow-down into your Node.js application, you can effectively manage the flow of requests, protecting your server from abuse and ensuring a smoother experience for legitimate users. These tools offer a flexible approach to handling high traffic and can be customized to meet the specific needs of your application.