API rate limiting with Node and Redis
Tags: api, softwaredevelopment, redis, tech
Published: 2020-07-01 17:58:11

---
title: API rate limiting with Node and Redis
published: true
date: 2020-06-29 13:49:10 UTC
tags: api,softwaredevelopment,redis,tech
canonical_url: https://codeburst.io/api-rate-limiting-with-node-and-redis-95354259c768
---

#### Slow your roll by building a simple rate limiter to improve the availability of your API-based services

![](https://cdn-images-1.medium.com/max/1024/1*1bDAJ5ASFQryFaN9Dygp3A.jpeg)<figcaption>Photo by <a href="https://unsplash.com/@ludo_photos?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ludovic Charlet</a> on <a href="/s/photos/limit?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption>

Rate limiting can protect and improve the availability of your API-based services. If you’re talking to an API and receive the HTTP **429 Too Many Requests** response status code, you’ve been rate limited. That means you’ve exceeded the number of requests allowed within a given period of time.

Slow your roll and wait a bit, before trying again.

### Why rate limit?

When you’re thinking about limiting your own API-based service, you need to balance tradeoffs between user experience, security, and performance.

![](https://cdn-images-1.medium.com/max/254/1*csTHv7389qESVQix6GZEjA.png)

The most common reason to control the flow of data is to maintain availability for your API-based services. But there’s security benefits too. A single unintentional, or intentional, surge in inbound traffic can tie up valuable resources and impact the availability for other users.

By controlling the rate of incoming requests, you can:

- protect services and resources from being overwhelmed
- slow down brute-force attacks
- prevent distributed denial-of-service (DDOS) attacks

### How can you implement rate limiting?

Rate limiting can be implemented at the client-level, application-level, infrastructure-level, or anywhere in between.

There’s a few ways to control inbound traffic to your API service.

- **By user**  — track calls made by a user with an API key, access token, or IP address
- **By geography**  — such as decreasing rate limits at peak times of the day for each geographic region
- **By server** —if you have multiple servers handling different calls to your API, you might implement stricter rate limits for access to more expensive resources

You can use any one, or combination of, these types of rate limiting.

![](https://cdn-images-1.medium.com/max/1024/1*RrIekWutAh4ec27YQbgXGA.png)

No matter how you choose to implement it, the goal of rate limiting is to establish a checkpoint to either **reject** or **pass through** requests to access your resources. Many programming languages and frameworks have inbuilt capabilities or middleware to do this. There’s also options for various rate limiting algorithms.

This is one way to make your own rate limiter with Node and Redis.

1. Create a Node app
2. Add a rate limiter with Redis
3. Test in Postman

> **💻 Check out [the code sample on GitHub](https://github.com/loopDelicious/rate-limiter).**

Before you begin, make sure you have [Node](https://nodejs.org/en/) and [Redis](https://redis.io/download) installed on your machine.

### Step 1: Create a Node app

Set up a new Node app from the command line. Walk through the CLI prompts, or add the `--yes` flag to accept the default options.

```
$ npm init --yes
```

Create a file called `index.js` for your entry point if you accepted the default option during the project setup.

```
$ touch index.js
```

Install the [Express](https://expressjs.com/) web framework, and initialize the server in `index.js`.

```
const express = require('express')
const app = express()
const port = process.env.PORT || 3000
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
```

Start the server from the command line.

```
$ node index.js
```

Back in `index.js`, create a route to first check the rate limit, and then allow access to resources if the user is not over the limit.

```
app.post('/', async (req, res) => {
  async function isOverLimit(ip) {
    // to define
  }
  // check rate limit
  let overLimit = await isOverLimit(req.ip)
  if (overLimit) {
    res.status(429).send('Too many requests - try again later')
    return
  }
  // allow access to resources
  res.send("Accessed the precious resources!")
})
```

![](https://cdn-images-1.medium.com/max/1024/1*x-etzkTJLlvSknvfO4Hc9Q.png)<figcaption>application-level rate limiting</figcaption>

In the next step, we’ll define the rate limiter function `isOverLimit()`.

### Step 2: Add a rate limiter with Redis

Redis is in-memory key-value data store, so it can retrieve data very quickly. It’s also pretty straightforward [to implement rate limiting with Redis](https://redis.io/commands/incr/#pattern-rate-limiter-1).

- Store a key like a user’s IP address
- Increment the number of calls made from that IP
- Expire the record after a specified timeframe

The rate limiting algorithm shown below is an example of a **sliding window counter**. A user who submits a modest number of calls, or spaces them out over time, never reaches a rate limit. A user who exceeds the maximum requests within a 10-second window must wait for enough time to pass to resume their requests.

![](https://cdn-images-1.medium.com/max/1024/1*vM3pDB9MlJdKmqL1JG8NDw.png)<figcaption>rate limiting algorithm: sliding window counter</figcaption>

Install a Redis client for Node called [ioredis](https://github.com/luin/ioredis) from the command line.

```
$ npm install ioredis
```

Start the Redis server locally.

```
$ redis-server
```

Then require and initialize the Redis client in `index.js`.

```
const redis = require('ioredis')
const client = redis.createClient({
  port: process.env.REDIS_PORT || 6379,
  host: process.env.REDIS_HOST || 'localhost',
})
client.on('connect', function () {
  console.log('connected');
});
```

Define the `isOverLimit()` function that we started writing in the previous step, by following this pattern from Redis [to keep a counter by IP](https://redis.io/commands/incr/#pattern-rate-limiter-1).

```
async function isOverLimit(ip) {
  let res
  try {
    res = await client.incr(ip)
  } catch (err) {
    console.error('isOverLimit: could not increment key')
    throw err
  }
  console.log(`${ip} has value: ${res}`)
  if (res > 10) {
    return true
  }
  client.expire(ip, 10)
}
```

And that’s our rate limiter.

When a user makes a call to the API, we check Redis to see if the user is over the limit. If they are, the API immediately returns the HTTP 429 status code with the message Too many requests — try again later. If the user is within the limit, we proceed to the next code block where we can allow access to protected resources like a database.

During the rate limit check, we find the user’s record in Redis and increment the count of their requests. If there’s no record of the user in Redis, then we create a new record. And lastly, each record will expire within 10 seconds of the latest activity.

In the next step, let’s make sure our rate limiter is working correctly.

### Step 3: Test in Postman

Save your changes, and restart the server. We’ll use [Postman](https://www.postman.com/) to send POST requests to our API server running locally at `http://localhost:3000`.

![](https://cdn-images-1.medium.com/max/1024/1*kxsoLjDFrRpOGpYzq9mbzA.png)<figcaption>within rate limit</figcaption>

Continue sending requests in rapid succession to hit your rate limit.

![](https://cdn-images-1.medium.com/max/1024/1*l-C_E7ZDp9SD-csDYQfzZA.gif)<figcaption>exceeds rate limit — HTTP 429 too many requests</figcaption>

### Final thoughts about rate limiting

This was a simple example of rate limiter with Node and Redis.

This is just the start. There’s a bunch of strategies and tools available to structure and implement your rate limits. And there’s other enhancements to explore with this example, like:

- Let the user know how much time they should wait before trying again, either in the response body or as a Retry-after header
- Log the requests reaching the rate limit, for insight into user behavior and to alert of malicious attacks
- Try a different rate limiting algorithm or other middleware

And remember, when you’re exploring API limits, you’re balancing tradeoffs between performance, security, and user experience. Your ideal solution for rate limiting will change over time along with these considerations.

* * *