from config import LOGGER, NotAuthenticated from fastapi import Request from fastapi.responses import JSONResponse from fastapi.exceptions import RequestValidationError from fastapi.exceptions import HTTPException, StarletteHTTPException from slowapi.errors import RateLimitExceeded async def rate_limited(request: Request, error: RateLimitExceeded) -> JSONResponse: n = 0 while True: if error.detail[n].isnumeric(): n += 1 else: break error.detail = error.detail[:n] + " requests" + error.detail[n:] LOGGER.info( f"{request.client.host} got rate-limited at {str(request.url)} " f"(exceeded {error.detail})" ) return JSONResponse( status_code=200, content={ "msg": f"Too many requests, retry after {error.detail[error.detail.find('per') + 4:]}", "status_code": 429, }, ) def not_authenticated(request: Request, _: NotAuthenticated) -> JSONResponse: LOGGER.info(f"{request.client.host} failed to authenticate at {str(request.url)}") return JSONResponse( status_code=200, content={ "msg": "Authentication is required", "status_code": 401, }, ) def request_invalid(request: Request, exc: RequestValidationError) -> JSONResponse: LOGGER.info( f"{request.client.host} sent an invalid request at {request.url!r}: {type(exc).__name__}: {exc}" ) return JSONResponse( status_code=200, content={ "msg": f"Bad request: {type(exc).__name__}: {exc}", "status_code": 400, }, ) def http_exception( request: Request, exc: HTTPException | StarletteHTTPException ) -> JSONResponse: if exc.status_code >= 500: LOGGER.error( f"{request.client.host} raised a {exc.status_code} error at {request.url!r}:" f"{type(exc).__name__}: {exc}" ) return JSONResponse( status_code=200, content={ "msg": "Internal server error", "status_code": exc.status_code, }, ) else: LOGGER.info( f"{request.client.host} raised an HTTP error ({exc.status_code}) at {str(request.url)}" ) return JSONResponse( status_code=200, content={ "msg": exc.detail, "status_code": exc.status_code, }, )