Rate Limiting in Express
Hey There, Hope you guys are doing well. Today we will be discussing how we can limit the rate request on a particular API, we call this terminology a Rate-Limiting.
Definition
Rate-limiting in API is used to control the rate of requests sent by clients having the same IP. It can be used to prevent Proxy data or DoS attacks and limit web scraping for the content.
Prerequisite
To make use of this article at the peak, one needs to know
- What is an API?
API(Application Programming Interface) is the communication unit between client and data (Can be database). You can think of a waiter as an API whereas data is a dish that is made by the chef and client as a customer.
- What are the Middlewares?
Before going to the actual logic to extract data for a client, a server can perform several other actions. for example, checking the validity of the request (For data consistency), caching the data and sending that data, checking the user headers (For security concerns), blocking a particular IP (Which is we are going to use today), etc.
Usecase
You will find many traditional definitions online but let’s discuss an actual scenario where you can make use of limiting the rate.
Let’s assume, you are a businessman of cars(Put whatever big brand you want to put here) and now you want to give a virtual demo for your client using videos on your website. You hire a service provider which is going to give you 1000 requests per month as your new trial as per your client base and business needs.
Now, after getting live with this feature you notice some of your clients are exhausting your 1000 limit as they are re-watching the video sessions. So you made a decision to let the user rewatch the video but not repeatedly or they can watch the video again after 30 seconds.
To achieve this result you came to me and I started making it a reality by adding another middleware into your system.
Get Started
Create App
Let’s create the above use-case into reality.
To begin, first create a folder here I name it rate-limiting-demo and open the vscode with the integrated terminal.
Once you open the terminal type a command
npm init -y
which will create a new project with the default settings, you can always go to your package.json file to make any necessary changes.
Next,
create a few folders and files
After creating the folder we can simply create our express application
npm i express
The above command will install the express in your folder then go ahead to your index.js and write a bunch of starters and default routes.
import express from 'express';const app = express();const PORT = 8080;
// create a route for the appapp.get('/', (req, res) => { res.send('Hello World');});
// default routeapp.use((req, res) => { res.status(404).send({ message : 'URL Not found!' })})// make the server listen to requests
app.listen(PORT, () => { console.log(`Server running at: http://localhost:${PORT}/`);});
and If you try to run your application using command node index then it will fail as we are not using commonJS syntax.
To make sure no error is prompt up we can add one line in our package.json
"type" : "module"
After writing this your package.json will look like this,
Now, if you run the application it will start listening at PORT 8080.
Add a Route and Controller
Now, go to the /routes folder and create an index.js file and paste this code
import { Router } from 'express';var router = Router();router.get('/video', function (req, res) { res.send('video sent');})export default router;
This will use an express router and attach another route ‘/video’ to it.
now move to the index.js and include this file there.
first, we need to import the file
import apiRouter from "./routes/index.js";
then before our default response use the apiRouter we just created
app.use('/api', apiRouter)
Once we include these lines our index.js will look like this
Now, let’s create an index.js file in the /controllers folder and paste this code
let remainingCounter = 1000;class VideoStreamer { validator = (req, res, next) => { next() } video = () => { return 'your controlled video stream' } getVideo = (req, res) => { let video = this.video() remainingCounter = remainingCounter - 1; res.status(200).send({ message : `Remaining count for video is ${remainingCounter}`, video }) }}export default new VideoStreamer();
and here is a screenshot of the code for better readability,
Let me deconstruct the code for you,
here we have created a class name VideoStreamer which will be handling our entire logic of the code and we have exported the class but don’t forget to export a new object from it
next, we have created a global variable named remainingCounter which is behaving as our total limit for the videos
We have also added 2 methods named getVideo(We are only sending the response with reducing the counter to -1) and validator(this will be our one of the middleware)
Note: This is not a tutorial for creating a counter application using express and MongoDB. So I have avoided that logic + I separate out streaming logic to independent functions to not mess with the actual topic.
Hope you understand the code :)
Next, Change the /routes/index.js to include the controller file
import Controller from './../controllers/index.js';
and update our route to new methods
router.get('/video', Controller.validator, Controller.getVideo)
After this step, our /routes/index.js will look like this,
Sober.
If we now run the application and go to the URL
http://localhost:8080/api/video
We will see this result
And every time we refresh the page, it will reduce the count
to -1, which is exactly what we are facing as a challenge in our use case.
Create Rate-Limiter
Now it’s time to create our rate limiter which will help us to reduce our issue.
first, install the package express-rate-limit which will be giving us the flexibility to write the efficient limiter.
npm install --save express-rate-limit
create /middlewares/rateLimiter.js file and paste the bunch of code there
import rateLimit from "express-rate-limit";const limiter = rateLimit({ windowMs: 6 * 1000, // 6 seconds max: 2 // limit each IP to 2 requests per windowMs });export default limiter;
The above code will freeze the window for 6 seconds once the 2 limits are reached, it will send the code 429 with the default message which you can configure.
Let’s attach this function to our route. Head back to the /routes/index.js and add one more middleware after importing the file.
import rateLimiter from './../middlewares/rateLimiter.js';
and updated route,
router.get('/video', rateLimiter, Controller.validator, Controller.getVideo)
The final result will look like this,
Now, if you go back to the browser, you will see a different result as your account will be blocked after a few successive results.
And here we will conclude that now you know a use case where you can use rate-limiting.
I hope you guys like this article. Please like and share to the one who is looking for rate limiter :) Have a great day. Thanks!