API Rate Limiting — Node.js
As developers, it’s really important to make sure the APIs we are running as efficiently as possible. Otherwise, users will suffer from slow performance.
Why you need API limiting?
Performance isn’t the only reason to limit API requests, either. API limiting, which is also known as rate limiting, is an essential component of Internet security, as DoS attacks can tank a server with unlimited API requests.
Rate limiting also helps make your API scalable. If your API blows up in popularity, there can be unexpected spikes in traffic, causing severe lag time.
How rate limits work?
Rate limits act as gatekeepers to control the amount of incoming or outgoing traffic to or from a network. An API rate limit might enforce, say, 100 requests per minute. Once requests exceed that number, it generates an error message to alert the requester that it exceeded the number of allotted requests in a specific time frame.
Types Of Rate Limits
- User rate Limiting
The most common type of rate-limiting, user rate limiting monitors a user’s API key, session cookie, and IP address to watch for the number of requests being made. If the number of requests exceeds the limit, the user must wait until the time frame resets, which is usually indicated by an amount of time to wait sent along via a message attached to the “Retry-After” header.
2. Time-based rate limiting
This is usually based on the region and time of day that the user is attempting to access a network. It exists to ensure that the strict rate-limiting protocols apply only to certain periods of time when traffic will be the highest. Often this involves increasing the number of requests allowed between the hours of 12 am and 8 am, since traffic tends to be at its lowest overall in that time period.
3. Server rate limiting
Depending on the size of the API, you may have multiple servers handling different types of requests. Server rate limiting is the process of enforcing different limits on a server-by-server basis.
How to implement rate-limiting in Node.js?
The express-rate-limit is a simple and straight forward library that solves this problem for us. It’s not the most complete one but is a lightweight and fast way to achieve this goal. For most refined options the express-rate-limit itself already recommends other libraries such as rate-limiter-flexible , express-brute and express-limiter.
Install & Setup
- First of all, you need a node.js project. So create a directory and execute the command
npm init -y
to create a default package.json file. - Then install the necessary packages for the application: the express and the express-rate-limit
npm install express express-rate-limit
- Setup express. To make it easier to execute update your package.json file and add a start script. It will let us to execute the project with the
npm start
command
...
"scripts": {
"start": "node index.js"
},
...
- Then create an index.js file in the root directory to be your entry point.
So you can place the most generic express start code.
// express import
const express = require('express')
// express initialization
const app = express()
const PORT = 3000
// generic GET route that we will use for the tests
app.get('/', function (req, res) {
return res.send('Hello World')
})
// server initialization
app.listen(PORT, () => {
console.log(`server started on port ${PORT}`)
})
- So when we run the
npm start
(ornode index.js
if you jumped the package.json step) it should display that message indicating that the application is working:
- And when accessing the
localhost:3000
in the "/" route it will display theHello World
that we configured.
Adding the rate limit
Since we already added the express-rate-limit in the first step we just have to start using it.
The express-rate-limit works as a middleware, which means that we can use it in a single route, the entire app, or a group of sub-routes.
For that, we just need to understand how express handles middlewares, but being very straight to the point we will use the use
function from express to add a middleware or request handler in the root of our API to wrap it entirely.
Now let’s use it:
- First, we need to import the express-rate-limit in our code just under the express import
// /index.js
const express = require('express')
const rateLimit = require('express-rate-limit')
// ...
- Then we can configure the time box in milliseconds and the maximum number of requests per IP address (max)
// /index.js
const express = require('express')
const rateLimit = require('express-rate-limit')
const app = express()const PORT = 3000// Create the rate limit rule
const apiRequestLimiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: 2 // limit each IP to 2 requests per windowMs
})// Use the limit rule as an application middleware
app.use(apiRequestLimiter)app.get('/', function (req, res) {
return res.send('Hello World')
})app.listen(PORT, () => {
console.log(`server started on port ${PORT}`)
})
So that will be the default response, that we had before:
And when the limit is exceeded it will display a default message Too many requests, please try again later.
:
And it’s already working!
To change this message we have two options:
- Add a “message” property inside the object passed as param for the
rateLimit
function
const apiRequestLimiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: 2, // limit each IP to 2 requests per windowMs
message: "Your limit exceeded"
})
2. Add a handler function to process the failure case:
const apiRequestLimiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: 2, // limit each IP to 2 requests per windowMs
handler: function (req, res, /*next*/) {
return res.status(429).json({
error: 'You sent too many requests. Please wait a while then try again'
})
}
})
And that’s it!
Thanks for reading!