54 Adding Rate Limiting and Throttling
54 Adding Rate Limiting and Throttling
Managing network traffic to an application is one of the essential aspects of building service-based software, especially APIs. As the number of users grows, an API must remain reliable and protected against abuse or attacks. Two techniques commonly used to address this are rate limiting and throttling. This article will help you understand and distinguish between the two and implement them, complete with code examples, simulations, and a simple visualization.
What Are Rate Limiting and Throttling?
Rate Limiting
Rate limiting is a technique for limiting the number of requests that can be made to a server within a given time period. For example, a maximum of 100 requests per minute per user.
Throttling
Throttling is the process of slowing down or delaying excessive requests rather than rejecting them outright. With throttling, requests are still processed but with a certain delay so the server does not become overloaded.
The fundamental difference:
- Rate limiting typically “rejects” requests as soon as they exceed the limit.
- Throttling “slows down” requests but does not reject them immediately.
| Technique | Action when the limit is exceeded | Example Response |
|---|---|---|
| Rate Limiting | Request rejected (HTTP 429) | {"error": "Too Many Requests"} |
| Throttling | Request processed more slowly | Latency increases, but the response is still delivered |
Why Do You Need Rate Limiting and Throttling?
- Improving security: Prevents brute force attacks, DDoS, and API scraping.
- Maintaining server stability: The load does not spike suddenly.
- Managing user experience: No single user can dominate.
- Cost control: Especially when using paid services billed per request.
Implementation Strategies
Some popular rate limiting strategies:
- Fixed Window — Counts requests within a fixed time window (e.g., every 1 minute).
- Sliding Window — Similar to fixed window, but more flexible.
- Token Bucket — Each request “consumes a token”. Tokens are refilled periodically.
- Leaky Bucket — Requests are processed at a steady rate through a queue, similar to throttling.
Diagram showing the difference between Fixed Window and Token Bucket:
sequenceDiagram
participant User
participant API
participant Bucket
User->>API: Send Request
API->>Bucket: Check Token
alt Token available
Bucket->>API: Take Token
API->>User: Process Request
else No token
API->>User: 429 Error (Rate Limited)
end
Case Study: Implementation in Node.js with ExpressJS
Installing the Middleware
For convenience, we’ll use express-rate-limit .
1npm install express express-rate-limitRate Limiting Implementation Example
1const express = require('express');
2const rateLimit = require('express-rate-limit');
3
4const app = express();
5
6// Set the rate limit: max 10 requests per 15 seconds per IP
7const limiter = rateLimit({
8 windowMs: 15 * 1000, // 15 seconds
9 max: 10,
10 message: {
11 error: "Too many requests, please try again later."
12 }
13});
14
15app.use(limiter);
16
17app.get('/api/data', (req, res) => {
18 res.json({ success: true, message: 'Data received!' });
19});
20
21app.listen(3000, () => console.log('Server up on port 3000'));Simulation: If a user makes more than 10 requests within 15 seconds, all subsequent requests will receive this response:
1{ "error": "Too many requests, please try again later." }Simple Throttling Implementation
Throttling can be implemented by slowing down the response using setTimeout. This is not the optimal technique, but it is illustrative enough.
1const slowDown = (req, res, next) => {
2 // Simulation: if there are more than 5 requests within a minute, delay by 1 second
3 if (!req.session) req.session = {};
4 req.session.requests = req.session.requests || [];
5 const now = Date.now();
6
7 // remove requests older than 1 minute
8 req.session.requests = req.session.requests.filter(ts => now - ts < 60 * 1000);
9 req.session.requests.push(now);
10
11 if (req.session.requests.length > 5) {
12 setTimeout(next, 1000); // delay 1 second
13 } else {
14 next();
15 }
16};
17
18app.use(slowDown);With the middleware above:
- Normal user: fast responses at < 5 requests/minute.
- Overused: every request beyond 5/minute is delayed by 1 second.
Simulation & Test Table
Testing with a Simple HTTP Client:
1for i in {1..12}; do curl -i http://localhost:3000/api/data; done| Request No. | Fixed Window (10/15s) | Time (Throttled after 5/min) |
|---|---|---|
| 1 - 10 | 200 OK | 0 ms (fast) |
| 11 - 12 | 429 Too Many Requests | 1000 ms (1-second delay) |
Best Practices
1. Use Redis for large-scale distribution
Middleware rate limiters are fine for dev/test, but for production and distributed scale, use Redis so that limits stay consistent across multiple server instances.
2. Limiting Granularity
You can apply limits based on:
- IP address
- API key
- User ID
- Endpoint
Adjust this to match your use case.
3. Return Limit Information
Return rate-limit headers so clients know their limits:
1HTTP/1.1 200 OK
2X-RateLimit-Limit: 10
3X-RateLimit-Remaining: 3
4X-RateLimit-Reset: 17174622004. Consider Burst & Throttle
Let small bursts pass through quickly, then throttle rather than reject afterward, so the UX stays smooth.
Conclusion
Applying rate limiting and throttling is a mandatory step for the reliability of modern APIs—protecting against overload and attacks while keeping things fair across users. Integrating them is easy with the help of middleware, but the key to success lies in choosing the right strategy, tuning the parameters, and monitoring.
Don’t forget, rate limiting and throttling are not a cure-all—combine them with caching, monitoring, and alerting for a truly reliable API.
If you’d like a more advanced code simulation or one that uses Redis, let me know in the comments or DM me! Happy building healthy and scalable APIs. 🚀