Rate-Limiter Middleware Function
Implement the middleware function to limit the API calls made from an IP address in a defined window.
We'll cover the following
We’ve learned about middleware functions and some of their use cases. Since our rate-limiting function can be used by multiple APIs in our app, we’ll create it as middleware. As discussed earlier, we’ll keep our middleware function to be configurable in terms of allowed API hits and the windows in seconds for different APIs. So, we’ll create a function named rateLimiter()
that accepts three parameters: the time in seconds denoting our window, the number of allowed hits from an IP address in that window, and a simple message to differentiate all the different API endpoint calls.
Now, to make this function a middleware, we need to accept three parameters: the request object, the response object, and the next()
function. Theref, we’ll return a function from our rateLimiter()
function. There’s an important concept in JavaScript named closures. Closures are a powerful concept. They allow functions to retain access to variables from their parent scope even after the parent function has finished executing. A closure is created when an inner function references variables from its outer function, forming a “closure” around those variables. In our case, the inner function creates a closure with our rateLimiter()
function, which means that the inner function will have access to all the three parameters that are passed to the rateLimiter()
function.
Implement the rate-limiter function
We’ll follow the steps mentioned below to implement our rate-limiter middleware function:
We get the IP address of the client making the API request. We check whether the request headers contain the
x-forwarded-for
field, which could contain the IP address if the request went through a proxy. Otherwise, we fall back on using the remote IP address of the client using thereq.connection
object.It’s possible that the IP address has an IPv4-mapped IPv6 address format, indicated by the
::ffff:
prefix before the actual IP. If this prefix exists, we need to remove it to extract the actual IPv4 address, which is represented in the format123.123.123.12
.We then use the
incr()
function for incrementing the value associated with a Redis key. The key is formed by concatenating theipAddress
and anapiMessage
to differentiate the number of API calls made to a particular API. Theincr()
method increases the value by one and returns the new value. If the key doesn’t exist, it creates the key-value pair with a value of0
, increments the value, and returns1
.We then check to see if the value returned by the
incr()
function is1
; if so, it means this is the first request made to an API by an IP address. So, we set the expiration time for the Redis key.If the value isn’t
1
, we use thettl()
function that returns the time left for the key to expire in Redis.Finally, we check if the value returned by the
incr()
function exceeds the maximum number of allowed API calls per IP address. If it does, we return a failure response. Otherwise, we return a success response.
Let’s now move to the code.
Get hands-on with 1400+ tech skills courses.