-
Notifications
You must be signed in to change notification settings - Fork 23
Add rate limiting with user and endpoint-specific limits #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,11 +10,19 @@ | |||||||||||
| from fastapi import FastAPI, HTTPException, Request | ||||||||||||
| from fastapi.middleware.cors import CORSMiddleware | ||||||||||||
| from fastapi.responses import Response | ||||||||||||
| from slowapi import _rate_limit_exceeded_handler | ||||||||||||
| from slowapi.errors import RateLimitExceeded | ||||||||||||
| from slowapi.middleware import SlowAPIMiddleware | ||||||||||||
| from utils.limiter import Limiter, get_remote_address, limiter | ||||||||||||
|
|
||||||||||||
| limiter = Limiter(key_func=get_remote_address) | ||||||||||||
| # limiter = Limiter(key_func=get_remote_address) | ||||||||||||
|
Comment on lines
+16
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix duplicate limiter definition. The limiter is imported from -from utils.limiter import Limiter, get_remote_address, limiter
+from utils.limiter import limiter
-limiter = Limiter(key_func=get_remote_address)
-# limiter = Limiter(key_func=get_remote_address)📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.12.2)18-18: Redefinition of unused (F811) 🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| @asynccontextmanager | ||||||||||||
| async def lifespan(app: FastAPI): | ||||||||||||
| # Startup | ||||||||||||
| app.state.limiter = limiter | ||||||||||||
| logger.info("Lifespan: Connecting to MongoDB...") | ||||||||||||
| await connect_to_mongo() | ||||||||||||
| logger.info("Lifespan: MongoDB connected.") | ||||||||||||
|
|
@@ -77,6 +85,9 @@ async def lifespan(app: FastAPI): | |||||||||||
| ) | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| app.add_middleware(SlowAPIMiddleware) | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| # Add a catch-all OPTIONS handler that should work for any path | ||||||||||||
| @app.options("/{path:path}") | ||||||||||||
| async def options_handler(request: Request, path: str): | ||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,20 +1,21 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fastapi==0.116.1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uvicorn[standard]==0.34.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python-jose[cryptography]==3.5.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| passlib[bcrypt]==1.7.4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python-multipart==0.0.20 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pydantic==2.11.7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pydantic-settings==2.1.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pymongo==4.13.1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| motor==3.7.1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| firebase-admin==6.9.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python-dotenv==1.0.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bcrypt==4.0.1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| email-validator==2.2.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fastapi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uvicorn[standard] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python-jose[cryptography] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| passlib[bcrypt] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python-multipart | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pydantic | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pydantic-settings | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pymongo | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| motor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| firebase-admin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python-dotenv | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bcrypt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| email-validator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maintain version pins for production stability. Removing version pins from all dependencies can lead to unpredictable builds and potential breaking changes when new versions are released. This affects reproducibility and production stability. Consider maintaining version pins for critical dependencies: -fastapi
-uvicorn[standard]
-python-jose[cryptography]
-passlib[bcrypt]
-python-multipart
-pydantic
-pydantic-settings
-pymongo
-motor
-firebase-admin
-python-dotenv
-bcrypt
-email-validator
+fastapi>=0.104.0,<1.0.0
+uvicorn[standard]>=0.24.0,<1.0.0
+python-jose[cryptography]>=3.3.0,<4.0.0
+passlib[bcrypt]>=1.7.4,<2.0.0
+python-multipart>=0.0.6,<1.0.0
+pydantic>=2.0.0,<3.0.0
+pydantic-settings>=2.0.0,<3.0.0
+pymongo>=4.5.0,<5.0.0
+motor>=3.3.0,<4.0.0
+firebase-admin>=6.2.0,<7.0.0
+python-dotenv>=1.0.0,<2.0.0
+bcrypt>=4.0.0,<5.0.0
+email-validator>=2.0.0,<3.0.0📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pytest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pytest-asyncio | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| httpx | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mongomock-motor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pytest-env | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pytest-cov | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pytest-mock | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| slowapi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| from slowapi import Limiter | ||
| from slowapi.util import get_remote_address | ||
|
|
||
| limiter = Limiter(key_func=get_remote_address) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| from slowapi.util import get_remote_address | ||
| from utils.limiter import limiter | ||
|
|
||
|
|
||
| def limit_all_routes(router, rate: str): | ||
| for route in router.routes: | ||
|
|
||
| print(route) | ||
| if hasattr(route, "endpoint"): | ||
|
|
||
| route.endpoint = limiter.limit(rate)(route.endpoint) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Remove unused import and verify limiter import path.
The
statusimport from FastAPI is unused and should be removed as indicated by static analysis. Also, verify that the limiter import path is correct relative to the backend directory structure.🏁 Script executed:
Length of output: 54
Remove unused FastAPI import
The
statussymbol isn’t referenced in this file, so it can be dropped. The limiter module path is correct (backend/utils/limiter.py), no change needed there.— limiter import verified at
backend/utils/limiter.py📝 Committable suggestion
🧰 Tools
🪛 Ruff (0.12.2)
10-10:
fastapi.statusimported but unusedRemove unused import:
fastapi.status(F401)
🤖 Prompt for AI Agents