Search code examples
node.jsmongodbredisrate-limiting

Node.js HTTP how to do an HTTP request rate limit?


I want to create a rate limit middleware for my express http handling, something like this:

app.post("/v1/authentication/login", rateLimiter(5, 20), require('./api/v1-login'));

Which the middleware will allow only 5 requests whitin 20 seconds.

I can use a plugin for that, but I am also working with clusters/processes and I have read that the plugin would not support processes.

I know I can share data between processes using a DB - MongoDB or Redis.

In addition I would like to make a custom rate limit - that means, for function A I want user John to be allowed to request 5 times in every 20 seconds for example, however, for the same function I want Dani to be allowed to send 10 requests per 20 seconds.

I also need this to be applied in all of the processes as I mentioned before.

I thought about writing my own script of saving the data of the requesting user, but I do not know what to exactly save - his IP? his chrome serial number or what ever it is..?

Should I store this in the Redis DB or Mongo? Maybe is there a Node.js built in memory which is better to save there the data instead?

What do you recommend?


Solution

  • There's nothing wrong to using a plugin. Take express-rate-limit with Redis Store for example, you can rate-limit the whole app per user IP and store this in Redis:

    const rateLimit = require("express-rate-limit");
    const RedisStore = require('rate-limit-redis');
    app.use(rateLimit({
      store: new RedisStore({ /* ... config */ });
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100 // limit each IP to 100 requests per windowMs
    });
    

    Or you can limit just a given endpoint:

    const someApiLimiter = rateLimit({
      windowMs: 5 * 60 * 1000,
      max: 12,
    });
    app.use('/api/some', someApiLimiter);
    

    By default req.ip is used, but you can provide a keyGenerator function, and use something like, say, combination of req.ip and req.user._id. So you're covered on all bases.

    I recommend Redis for these things as it's a lot of small data that you need fast, Redis does these things well.