Skip to content

Commit 7219b33

Browse files
authored
Ratelimit (#2)
* Using UPSTASH_REDIS_REST_API as database * Added ratelimit
1 parent 26d40ea commit 7219b33

File tree

4 files changed

+50
-4
lines changed

4 files changed

+50
-4
lines changed

api/helper.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Crypto from 'node:crypto';
2-
import { kv } from '@vercel/kv';
2+
import { createClient } from '@vercel/kv';
33

44
const secret = process.env.SECRET;
55
const sigLen = parseInt(process.env.SIG_LEN);
@@ -10,6 +10,10 @@ const dbKeyPrefix = {
1010
oneToMany: "o2m:",
1111
oneToOne: "o2o:",
1212
}
13+
const kv = createClient({
14+
url: process.env.UPSTASH_REDIS_REST_URL,
15+
token: process.env.UPSTASH_REDIS_REST_TOKEN,
16+
})
1317

1418
function hash(str){
1519
return Crypto.hash('md5', str, 'base64url').substr(0,hashLen);

example.env

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ HASH_LEN=5 # Hash character count
1010
TTL=86400 # Time to live for data in seconds
1111
BODYLIMIT=10000 # Max content-length in bytes. Note: 1 byte = 1 character.
1212
FIELDLIMIT = 5 # Max length of the one-to-one token
13+
RATELIMIT= 20 # Max number of requests within following time period
14+
RATELIMIT_WINDOW = '300 s'
1315

14-
# Redis credentials
15-
KV_URL=
16+
# Redis credentials to be used for rate-limiting
1617
KV_REST_API_URL=
1718
KV_REST_API_TOKEN=
18-
KV_REST_API_READ_ONLY_TOKEN=
19+
20+
# Redis credentials to be used for database
21+
UPSTASH_REDIS_REST_URL=
22+
UPSTASH_REDIS_REST_TOKEN=

middleware.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Refs:
3+
https://vercel.com/guides/rate-limiting-edge-middleware-vercel-kv
4+
https://vercel.com/docs/functions/edge-middleware/middleware-api
5+
https://upstash.com/docs/redis/sdks/ratelimit-ts/features#caching
6+
https://upstash.com/docs/redis/sdks/ratelimit-ts/methods#limit
7+
*/
8+
import { ipAddress } from '@vercel/functions'
9+
import { next } from '@vercel/edge'
10+
import { Ratelimit } from '@upstash/ratelimit'
11+
import { kv } from '@vercel/kv'
12+
13+
const cache = new Map(); // must be outside of your serverless function handler
14+
15+
const ratelimit = new Ratelimit({
16+
redis: kv,
17+
ephemeralCache: cache,
18+
analytics: false,
19+
limiter: Ratelimit.slidingWindow(parseInt(process.env.RATELIMIT), process.env.RATELIMIT_WINDOW),
20+
})
21+
22+
export default async function middleware(request) {
23+
// You could alternatively limit based on user ID or similar
24+
const ip = ipAddress(request) || '127.0.0.1'
25+
const { success, reset } = await ratelimit.limit(
26+
ip
27+
)
28+
29+
return success ? next() : Response.json(
30+
{ message: `Try after ${(reset - Date.now())/1000} seconds`, error: "Too Many Requests", statusCode: 429 },
31+
{
32+
status: 429,
33+
},
34+
)
35+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
"dependencies": {
33
"@fastify/cors": "^10.0.1",
44
"@fastify/formbody": "^8.0.1",
5+
"@upstash/ratelimit": "^2.0.3",
6+
"@vercel/edge": "^1.1.2",
7+
"@vercel/functions": "^1.4.2",
58
"@vercel/kv": "^2.0.0",
69
"fastify": "^5.0.0"
710
},

0 commit comments

Comments
 (0)