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;