Implementing Robust API Rate Limiting in Node.js with express-rate-limit
📚 Quick Review: This practical application is built upon a fundamental programming concept. Review the Theory Lesson here first.
Prerequisites
Before we dive into the implementation, ensure you have the following set up:
- Node.js installed on your machine.
- npm (Node Package Manager), which comes with Node.js.
- A basic Express.js application. If you don’t have one, we’ll quickly set up a minimal example.
Installation
First, you need to install the necessary packages.
Step 1: Initialize Your Project (if not already done)
If you’re starting a new project, navigate to your project directory in the terminal and run:
npm init -y
This command creates a `package.json` file, which manages your project’s dependencies.
Step 2: Install Express and `express-rate-limit`
Now, install Express (if you don’t have it) and the `express-rate-limit` package:
npm install express express-rate-limit
The Rate Limiting Configuration Explained
Let’s look at the provided code snippet and break down each part of the `express-rate-limit` configuration. This code typically resides in a separate file, for example, `apiLimiter.js`.
const rateLimit = require('express-rate-limit');
// Configure request limits: Allow 100 requests per IP address every 15 minutes
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: {
status: 429,
error: 'Too many requests from this IP, please try again after 15 minutes.'
},
standardHeaders: true,
legacyHeaders: false,
});
// Apply protection to all API routes
// app.use('/api/', apiLimiter);
module.exports = apiLimiter;
Line-by-Line Breakdown:
- `const rateLimit = require(‘express-rate-limit’);`: This line imports the `express-rate-limit` middleware into our Node.js application. It makes the rate limiting functionality available for use.
- `const apiLimiter = rateLimit({…});`: Here, we are creating an instance of our rate limiter. The `rateLimit()` function is called with a configuration object that defines the rules for our API.
- `windowMs: 15 * 60 * 1000,`: This crucial option defines the time window for which requests are counted. `15 * 60 * 1000` calculates to 15 minutes (15 minutes * 60 seconds/minute * 1000 milliseconds/second). All requests from a single IP within this 15-minute window will be tracked.
- `max: 100,`: This sets the maximum number of requests allowed from a single IP address within the `windowMs` timeframe. In this case, an IP can make up to 100 requests every 15 minutes.
- `message: {…},`: When an IP exceeds the `max` requests within the `windowMs`, this `message` object will be sent back as the response. It includes an HTTP `status` code of `429` (Too Many Requests) and a user-friendly `error` message.
- `standardHeaders: true,`: This option enables the `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` headers in the response. These headers provide clients with information about their current rate limit status, helping them manage their requests.
- `legacyHeaders: false,`: This disables the older `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers. It’s generally recommended to use the `standardHeaders` for modern applications.
- `// app.use(‘/api/’, apiLimiter);`: This commented-out line shows how you would apply the `apiLimiter` middleware to your Express application. By using `app.use(‘/api/’, apiLimiter);`, all routes starting with `/api/` would be protected by this rate limit. You can also apply it to specific routes or globally.
- `module.exports = apiLimiter;`: This line exports the configured `apiLimiter` instance, making it available for other files in your Node.js project to import and use.
Integrating the Rate Limiter into an Express Application
Now, let’s see how to use this `apiLimiter` in a typical Express application. Create a file named `app.js` (or your main server file) and add the following code:
Example `app.js`
const express = require('express');
const apiLimiter = require('./apiLimiter'); // Assuming the above code is in apiLimiter.js
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
// Apply the rate limiter to all API routes starting with /api/
app.use('/api/', apiLimiter);
// A protected API endpoint
app.get('/api/data', (req, res) => {
res.json({ message: 'This is your API data! You accessed a protected route.' });
});
// An unprotected route
app.get('/', (req, res) => {
res.send('Welcome to the homepage. API is protected at /api/data');
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
To run this application, save both `apiLimiter.js` and `app.js` in the same directory, then open your terminal in that directory and execute:
node app.js
Testing Your Rate Limiter
Once your server is running, you can test the rate limit using tools like `curl` or Postman.
Using `curl` in your terminal:
# Make 100 requests (these should succeed)
for i in $(seq 1 100); do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/api/data; done
# Make the 101st request (this should fail with 429)
curl -v http://localhost:3000/api/data
You should observe the first 100 requests returning a `200 OK` status, and the 101st request (and subsequent ones within the 15-minute window) returning a `429 Too Many Requests` status, along with your custom error message. Also, check the response headers for `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` to see the current status.
1 comment