I needed to do quick and simple rate-limiting this week. Here's a solution I came to, using Upstash.

js
1import upstash from '@upstash/redis';
2
3const redis = upstash({
4 url: process.env.UPSTASH_REST_URL,
5 token: process.env.UPSTASH_REST_TOKEN,
6});
7
8export const hashKey = (apiKey: string, minute: number) => {
9 return `limits:${apiKey}:${minute}`;
10};
11
12export const checkLimit = async (apiKey: string) => {
13 const minute = new Date().getMinutes();
14 const key = hashKey(apiKey, minute);
15 const currentLimit = await redis.get(key);
16
17 // Test if limit is reached and throw error if it is
18 if (currentLimit.data) {
19 const count = parseInt(currentLimit.data, 10);
20 if (count > 1000) { // 1000 requests per minute
21 console.error('todo, handle overage here');
22 }
23 }
24
25 // Increment the rate limit counter and ensure it expires in 59 min
26 // Note that if the key is not found, it will be created
27 redis.incr(key);
28 redis.expire(key, 59 * 60); // Expire in 59 minutes
29
30 return currentLimit.data ? parseInt(currentLimit.data, 10) : 1;
31};

Using Redis

I assume you can do the same thing with Redis (maybe using something like ioredis npm). You can probably optimize it further by using MULTI (i.e. transactions), so it all will happen in one swoop.

Sign up and get the latest friction log studies, blog articles and podcast updates

© 2021 Friction Log. All Rights Reserved.