First implementation API for PIP (Proyecto: Pharmacy Integration Platform)
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import time
|
||||
|
||||
from fastapi import Request, Response
|
||||
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
||||
|
||||
from src.infrastructure.config.settings import settings
|
||||
|
||||
|
||||
class RateLimitMiddleware(BaseHTTPMiddleware):
|
||||
def __init__(self, app, requests_per_minute: int | None = None):
|
||||
super().__init__(app)
|
||||
self._rpm = requests_per_minute or settings.RATE_LIMIT_PER_MINUTE
|
||||
self._clients: dict[str, list[float]] = {}
|
||||
|
||||
async def dispatch(
|
||||
self, request: Request, call_next: RequestResponseEndpoint
|
||||
) -> Response:
|
||||
if request.method == "OPTIONS":
|
||||
return await call_next(request)
|
||||
|
||||
path = request.url.path
|
||||
if path.startswith("/docs") or path.startswith("/redoc") or path.startswith("/openapi") or path.startswith("/metrics"):
|
||||
return await call_next(request)
|
||||
|
||||
client_key = self._get_client_key(request)
|
||||
now = time.monotonic()
|
||||
window = self._clients.setdefault(client_key, [])
|
||||
window[:] = [t for t in window if now - t < 60]
|
||||
|
||||
if len(window) >= self._rpm:
|
||||
return Response(
|
||||
content='{"error":{"code":"RATE_LIMIT_EXCEEDED","message":"Rate limit exceeded. Try again later."}}',
|
||||
status_code=429,
|
||||
media_type="application/json",
|
||||
headers={"Retry-After": "60"},
|
||||
)
|
||||
|
||||
window.append(now)
|
||||
response = await call_next(request)
|
||||
remaining = self._rpm - len(window)
|
||||
response.headers["X-RateLimit-Limit"] = str(self._rpm)
|
||||
response.headers["X-RateLimit-Remaining"] = str(max(0, remaining))
|
||||
response.headers["X-RateLimit-Reset"] = str(int(time.time()) + 60)
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
def _get_client_key(request: Request) -> str:
|
||||
forwarded = request.headers.get("x-forwarded-for")
|
||||
if forwarded:
|
||||
return forwarded.split(",")[0].strip()
|
||||
if request.client:
|
||||
return request.client.host
|
||||
return "unknown"
|
||||
Reference in New Issue
Block a user