From ddb01b679b222df682fc6e685deb40594eb3c0a7 Mon Sep 17 00:00:00 2001
From: vickysomtee <vickysomtee@gmail.com>
Date: Sun, 13 Aug 2023 12:29:01 +0100
Subject: [PATCH 1/3] feat: add rate limiter

---
 src/middleware/rateLimiter.ts |  9 +++++++++
 src/routers/router.js         | 22 ++++++++--------------
 src/routers/routerV2.js       |  9 +++++----
 3 files changed, 22 insertions(+), 18 deletions(-)
 create mode 100644 src/middleware/rateLimiter.ts

diff --git a/src/middleware/rateLimiter.ts b/src/middleware/rateLimiter.ts
new file mode 100644
index 00000000..45daa04f
--- /dev/null
+++ b/src/middleware/rateLimiter.ts
@@ -0,0 +1,9 @@
+import rateLimit from 'express-rate-limit';
+
+export const rateLimiter = rateLimit({
+  windowMs: 15 * 60 * 1000, // 15 minutes in milliseconds
+  max: 20,
+  message: 'Too many requests, please try again later',
+  standardHeaders: true,
+  legacyHeaders: false,
+});
diff --git a/src/routers/router.js b/src/routers/router.js
index e638d3bb..daefe9b7 100644
--- a/src/routers/router.js
+++ b/src/routers/router.js
@@ -1,9 +1,10 @@
 import express from 'express';
-import rateLimit from 'express-rate-limit';
 import { getWords, getWord } from '../controllers/words';
 import { getExamples, getExample } from '../controllers/examples';
 import { postDeveloper } from '../controllers/developers';
 import { getStats } from '../controllers/stats';
+import { rateLimiter } from '../middleware/rateLimiter';
+
 import validId from '../middleware/validId';
 import validateDeveloperBody from '../middleware/validateDeveloperBody';
 import validateApiKey from '../middleware/validateApiKey';
@@ -13,23 +14,16 @@ import analytics from '../middleware/analytics';
 
 const router = express.Router();
 
-const FIFTEEN_MINUTES = 15 * 60 * 1000;
-const REQUESTS_PER_MS = 20;
-const createDeveloperLimiter = rateLimit({
-  windowMs: FIFTEEN_MINUTES,
-  max: REQUESTS_PER_MS,
-});
-
 // Google Analytics
 router.use(analytics);
 
-router.get('/words', validateApiKey, attachRedisClient, getWords);
-router.get('/words/:id', validateApiKey, validId, attachRedisClient, getWord);
-router.get('/examples', validateApiKey, attachRedisClient, getExamples);
-router.get('/examples/:id', validateApiKey, validId, attachRedisClient, getExample);
+router.get('/words', rateLimiter, validateApiKey, attachRedisClient, getWords);
+router.get('/words/:id', rateLimiter, validateApiKey, validId, attachRedisClient, getWord);
+router.get('/examples', rateLimiter, validateApiKey, attachRedisClient, getExamples);
+router.get('/examples/:id', rateLimiter, validateApiKey, validId, attachRedisClient, getExample);
 
-router.post('/developers', createDeveloperLimiter, validateDeveloperBody, postDeveloper);
+router.post('/developers', rateLimiter, validateDeveloperBody, postDeveloper);
 
-router.get('/stats', validateAdminApiKey, attachRedisClient, getStats);
+router.get('/stats', rateLimiter, validateAdminApiKey, attachRedisClient, getStats);
 
 export default router;
diff --git a/src/routers/routerV2.js b/src/routers/routerV2.js
index 80980a17..4fe5787f 100644
--- a/src/routers/routerV2.js
+++ b/src/routers/routerV2.js
@@ -5,13 +5,14 @@ import validId from '../middleware/validId';
 import validateApiKey from '../middleware/validateApiKey';
 import analytics from '../middleware/analytics';
 import attachRedisClient from '../middleware/attachRedisClient';
+import { rateLimiter } from '../middleware/rateLimiter';
 
 const routerV2 = express.Router();
 
-routerV2.get('/words', analytics, validateApiKey, attachRedisClient, getWords);
-routerV2.get('/words/:id', analytics, validateApiKey, validId, attachRedisClient, getWord);
-routerV2.get('/examples', analytics, validateApiKey, attachRedisClient, getExamples);
-routerV2.get('/examples/:id', analytics, validateApiKey, validId, attachRedisClient, getExample);
+routerV2.get('/words', rateLimiter, analytics, validateApiKey, attachRedisClient, getWords);
+routerV2.get('/words/:id', rateLimiter, analytics, validateApiKey, validId, attachRedisClient, getWord);
+routerV2.get('/examples', rateLimiter, analytics, validateApiKey, attachRedisClient, getExamples);
+routerV2.get('/examples/:id', rateLimiter, analytics, validateApiKey, validId, attachRedisClient, getExample);
 
 // Redirects to V1
 routerV2.post('/developers', (_, res) => res.redirect('/api/v1/developers'));

From d694a728733f6696d09465ebd7519f6ba2cff1af Mon Sep 17 00:00:00 2001
From: vickysomtee <vickysomtee@gmail.com>
Date: Wed, 6 Sep 2023 00:59:17 +0100
Subject: [PATCH 2/3] feat: simplify middleware calls

---
 src/routers/router.ts   | 13 ++++++-------
 src/routers/routerV2.ts | 10 ++++++----
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/routers/router.ts b/src/routers/router.ts
index 4f77d740..34a65b50 100644
--- a/src/routers/router.ts
+++ b/src/routers/router.ts
@@ -14,15 +14,14 @@ import { rateLimiter } from '../middleware/rateLimiter';
 
 const router = express.Router();
 
-// Google Analytics
-router.use(analytics);
+router.use(analytics, rateLimiter);
 
-router.get('/words', rateLimiter, validateApiKey, attachRedisClient, getWords);
-router.get('/words/:id', rateLimiter, validateApiKey, validId, attachRedisClient, getWord);
-router.get('/examples', rateLimiter, validateApiKey, attachRedisClient, getExamples);
-router.get('/examples/:id', rateLimiter, validateApiKey, validId, attachRedisClient, getExample);
+router.get('/words', validateApiKey, attachRedisClient, getWords);
+router.get('/words/:id', validateApiKey, validId, attachRedisClient, getWord);
+router.get('/examples', validateApiKey, attachRedisClient, getExamples);
+router.get('/examples/:id', validateApiKey, validId, attachRedisClient, getExample);
 
-router.post('/developers', rateLimiter, validateDeveloperBody, postDeveloper);
+router.post('/developers', validateDeveloperBody, postDeveloper);
 
 router.get('/stats', rateLimiter, validateAdminApiKey, attachRedisClient, getStats);
 
diff --git a/src/routers/routerV2.ts b/src/routers/routerV2.ts
index 4fe5787f..d5667347 100644
--- a/src/routers/routerV2.ts
+++ b/src/routers/routerV2.ts
@@ -9,10 +9,12 @@ import { rateLimiter } from '../middleware/rateLimiter';
 
 const routerV2 = express.Router();
 
-routerV2.get('/words', rateLimiter, analytics, validateApiKey, attachRedisClient, getWords);
-routerV2.get('/words/:id', rateLimiter, analytics, validateApiKey, validId, attachRedisClient, getWord);
-routerV2.get('/examples', rateLimiter, analytics, validateApiKey, attachRedisClient, getExamples);
-routerV2.get('/examples/:id', rateLimiter, analytics, validateApiKey, validId, attachRedisClient, getExample);
+routerV2.use(rateLimiter);
+
+routerV2.get('/words', analytics, validateApiKey, attachRedisClient, getWords);
+routerV2.get('/words/:id', analytics, validateApiKey, validId, attachRedisClient, getWord);
+routerV2.get('/examples', analytics, validateApiKey, attachRedisClient, getExamples);
+routerV2.get('/examples/:id', analytics, validateApiKey, validId, attachRedisClient, getExample);
 
 // Redirects to V1
 routerV2.post('/developers', (_, res) => res.redirect('/api/v1/developers'));

From 57d345d39c28d53f7ab92d7e0ceff17697647bfe Mon Sep 17 00:00:00 2001
From: vickysomtee <vickysomtee@gmail.com>
Date: Mon, 11 Sep 2023 17:05:08 +0100
Subject: [PATCH 3/3] fix: update PR

---
 src/routers/router.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/routers/router.ts b/src/routers/router.ts
index 34a65b50..8bb832b7 100644
--- a/src/routers/router.ts
+++ b/src/routers/router.ts
@@ -23,6 +23,6 @@ router.get('/examples/:id', validateApiKey, validId, attachRedisClient, getExamp
 
 router.post('/developers', validateDeveloperBody, postDeveloper);
 
-router.get('/stats', rateLimiter, validateAdminApiKey, attachRedisClient, getStats);
+router.get('/stats', validateAdminApiKey, attachRedisClient, getStats);
 
 export default router;