Skip to content

Commit fabe5ca

Browse files
Merge pull request #37 from hemanth5055/add-rate-limiting
add IP-based rate limiting to Cloudflare Worker
2 parents c174350 + 3c879c0 commit fabe5ca

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

backend/src/index.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GoogleGenerativeAI } from '@google/generative-ai';
22

33
export interface Env {
4+
RATE_LIMIT: KVNamespace;
45
GEMINI_API_KEY: string;
56
}
67

@@ -10,6 +11,33 @@ const corsHeaders = {
1011
'Access-Control-Allow-Headers': 'Content-Type',
1112
};
1213

14+
const MAX_REQUESTS_ALLOWED = 10;
15+
const DURATION = 60_000;
16+
17+
async function checkRateLimit(ip: string, env: Env) {
18+
const key = `ip_key:${ip}`;
19+
const now = Date.now();
20+
let value = await env.RATE_LIMIT.get(key);
21+
let data = { count: 0, time: now };
22+
23+
if (value) {
24+
try {
25+
data = JSON.parse(value);
26+
} catch {
27+
data = { count: 0, time: now };
28+
}
29+
}
30+
31+
if (now - data.time > DURATION) {
32+
data.count = 0;
33+
data.time = now;
34+
}
35+
36+
data.count += 1;
37+
await env.RATE_LIMIT.put(key, JSON.stringify(data), { expirationTtl: 65 });
38+
39+
return data.count <= MAX_REQUESTS_ALLOWED;
40+
}
1341
async function handleTranslate(request: Request, model: ReturnType<GoogleGenerativeAI['getGenerativeModel']>) {
1442
const { code, targetLanguage } = await request.json<{ code: string; targetLanguage: string }>();
1543

@@ -73,11 +101,22 @@ export default {
73101
}
74102

75103
try {
104+
const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
105+
const allowed = await checkRateLimit(ip, env);
106+
if (!allowed) {
107+
return new Response(JSON.stringify({ error: "Too many requests. Try again later." }), {
108+
status: 429,
109+
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
110+
});
111+
}
76112
const url = new URL(request.url);
77113
const path = url.pathname;
78114
const genAI = new GoogleGenerativeAI(env.GEMINI_API_KEY);
79115
const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' });
80116

117+
if(path==="/test-rate-limit"){
118+
return new Response(JSON.stringify("Proceed !"))
119+
}
81120
if (path === '/' || path === '/v1/translate') {
82121
return await handleTranslate(request, model);
83122
}

backend/worker-configuration.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Runtime types generated with workerd@1.20250712.0 2025-07-15
44
declare namespace Cloudflare {
55
interface Env {
6+
RATE_LIMIT: KVNamespace;
67
}
78
}
89
interface Env extends Cloudflare.Env {}

backend/wrangler.jsonc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@
99
"compatibility_date": "2025-07-15",
1010
"observability": {
1111
"enabled": true
12-
}
12+
},
13+
"kv_namespaces": [
14+
{
15+
"binding": "RATE_LIMIT",
16+
"id": "<your_kv_id>"
17+
}
18+
]
19+
1320
/**
1421
* Smart Placement
1522
* Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement

0 commit comments

Comments
 (0)