This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
from http import HTTPStatus
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from app.api.router import api_router
|
||||
from app.core.config import settings
|
||||
from app.schemas.errors import ApiErrorResponse
|
||||
|
||||
|
||||
def _error_name(status_code: int) -> str:
|
||||
try:
|
||||
phrase = HTTPStatus(status_code).phrase
|
||||
except ValueError:
|
||||
return "HTTP_ERROR"
|
||||
return re.sub(r"[^A-Z0-9]+", "_", phrase.upper()).strip("_")
|
||||
|
||||
|
||||
def _error_message(detail: Any) -> str | list[str]:
|
||||
if isinstance(detail, str):
|
||||
return detail
|
||||
if isinstance(detail, list):
|
||||
messages = [
|
||||
str(item.get("msg", item)) if isinstance(item, dict) else str(item)
|
||||
for item in detail
|
||||
]
|
||||
return messages or "Request validation failed."
|
||||
return str(detail)
|
||||
|
||||
|
||||
def _error_payload(
|
||||
request: Request,
|
||||
status_code: int,
|
||||
message: str | list[str],
|
||||
error: str,
|
||||
) -> dict[str, Any]:
|
||||
return ApiErrorResponse(
|
||||
code=error,
|
||||
message=message,
|
||||
error=error,
|
||||
statusCode=status_code,
|
||||
path=request.url.path,
|
||||
).model_dump(by_alias=True)
|
||||
|
||||
|
||||
async def _http_exception_handler(
|
||||
request: Request,
|
||||
exception: HTTPException,
|
||||
) -> JSONResponse:
|
||||
error = _error_name(exception.status_code)
|
||||
return JSONResponse(
|
||||
status_code=exception.status_code,
|
||||
content=_error_payload(
|
||||
request,
|
||||
exception.status_code,
|
||||
_error_message(exception.detail),
|
||||
error,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def _validation_exception_handler(
|
||||
request: Request,
|
||||
exception: RequestValidationError,
|
||||
) -> JSONResponse:
|
||||
return JSONResponse(
|
||||
status_code=422,
|
||||
content=_error_payload(
|
||||
request,
|
||||
422,
|
||||
_error_message(exception.errors()),
|
||||
"VALIDATION_ERROR",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _register_exception_handlers(application: FastAPI) -> None:
|
||||
application.add_exception_handler(HTTPException, _http_exception_handler)
|
||||
application.add_exception_handler(
|
||||
RequestValidationError,
|
||||
_validation_exception_handler,
|
||||
)
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
error_responses = {
|
||||
status_code: {"model": ApiErrorResponse}
|
||||
for status_code in (400, 401, 403, 404, 422, 500)
|
||||
}
|
||||
application = FastAPI(
|
||||
title=settings.app_name,
|
||||
root_path=settings.docs_root_path,
|
||||
responses=error_responses,
|
||||
)
|
||||
_register_exception_handlers(application)
|
||||
application.include_router(api_router)
|
||||
return application
|
||||
|
||||
|
||||
app = create_app()
|
||||
Reference in New Issue
Block a user