For many reasons you may need to limit your API calls: It can be to avoid extra cost in cloud, to create a free tier to use your API, to fulfill a third-party API requirement, to prevent performance issues... I believe if you are reading this post this purpose is very clear in your mind and you are just trying to figure out how to make it work. So let's focus on this.
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.
Now starting
Installing packages
First of all you need a node.js project. So I created a directory and executed the command npm init -y
to create a default package.json file.
Then I will install the necessary packages for this application: the express and the express-rate-limit
npm install express express-rate-limit
Setup express
To make it easier to execute I will update my 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 I will create an index.js file in the root directory to be our entry point.
So I'll 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
(or node 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 the Hello 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 work as a middleware, it 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 the 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.
If you want to understand more about the middleware usage by express you can check the express documentation.
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 (windowMs) 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" })
-
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' }) } })
BONUS
You can also use a function handler to start billing the consumer for the exceeded requests
const apiRequestLimiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: 2, // limit each IP to 2 requests per windowMs
handler: function (req, res, next) {
applyFeesForConsumer()
next()
}
})
That way you will not block the request, just apply fees before continue.
And that's it!
Thank you
Thank you for reading this.
There are more available features and configurations in the express-rate-limit documentation it was just a simple example how we can use this library to control the API requests.
The examples and step-by-step are available in this repository branches.
I hope it helps you!
Top comments (5)
So simple with that billing for extra API calls! 😃
Nice article !
It would be nice if you can suggest an average rate limit. :)
Great tip in the bonus section! Thank you for the article.
Really great article... Thank you so much.. 🙏🏻
Great tutorial thanks!
But I can't find a way to retrieve the message anywhere (to put it in an alert() for example) without reloading the entire page, a bit like a 'fetch'.