initial project setup with README and ignore
This commit is contained in:
112
app/core/exception_handlers.py
Normal file
112
app/core/exception_handlers.py
Normal file
@@ -0,0 +1,112 @@
|
||||
"""Professional exception handlers for the API."""
|
||||
|
||||
import logging
|
||||
from fastapi import Request, status
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
from app.core.exceptions import APIException
|
||||
from app.models.errors import ErrorResponse, ErrorDetail
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def api_exception_handler(request: Request, exc: APIException) -> JSONResponse:
|
||||
"""Handle custom API exceptions."""
|
||||
request_id = getattr(request.state, "request_id", None)
|
||||
|
||||
error_response = ErrorResponse(
|
||||
success=False,
|
||||
error=ErrorDetail(
|
||||
field=exc.field,
|
||||
message=exc.message,
|
||||
code=exc.code
|
||||
),
|
||||
path=request.url.path,
|
||||
request_id=request_id
|
||||
)
|
||||
|
||||
logger.warning(f"API Exception: {exc.code} - {exc.message} (Request ID: {request_id})")
|
||||
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content=error_response.model_dump(exclude_none=True)
|
||||
)
|
||||
|
||||
|
||||
async def http_exception_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse:
|
||||
"""Handle HTTP exceptions."""
|
||||
request_id = getattr(request.state, "request_id", None)
|
||||
|
||||
error_response = ErrorResponse(
|
||||
success=False,
|
||||
error=ErrorDetail(
|
||||
message=exc.detail,
|
||||
code="HTTP_ERROR"
|
||||
),
|
||||
path=request.url.path,
|
||||
request_id=request_id
|
||||
)
|
||||
|
||||
logger.warning(f"HTTP Exception: {exc.status_code} - {exc.detail} (Request ID: {request_id})")
|
||||
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content=error_response.model_dump(exclude_none=True)
|
||||
)
|
||||
|
||||
|
||||
async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
|
||||
"""Handle validation errors with detailed field information."""
|
||||
request_id = getattr(request.state, "request_id", None)
|
||||
|
||||
errors = exc.errors()
|
||||
if errors:
|
||||
first_error = errors[0]
|
||||
field = ".".join(str(loc) for loc in first_error.get("loc", []))
|
||||
message = first_error.get("msg", "Validation error")
|
||||
else:
|
||||
field = None
|
||||
message = "Validation error"
|
||||
|
||||
error_response = ErrorResponse(
|
||||
success=False,
|
||||
error=ErrorDetail(
|
||||
field=field,
|
||||
message=message,
|
||||
code="VALIDATION_ERROR"
|
||||
),
|
||||
path=request.url.path,
|
||||
request_id=request_id
|
||||
)
|
||||
|
||||
logger.warning(f"Validation Error: {message} (Field: {field}, Request ID: {request_id})")
|
||||
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
content=error_response.model_dump(exclude_none=True)
|
||||
)
|
||||
|
||||
|
||||
async def general_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
||||
"""Handle unexpected exceptions."""
|
||||
request_id = getattr(request.state, "request_id", None)
|
||||
|
||||
error_response = ErrorResponse(
|
||||
success=False,
|
||||
error=ErrorDetail(
|
||||
message="An unexpected error occurred. Please try again later.",
|
||||
code="INTERNAL_SERVER_ERROR"
|
||||
),
|
||||
path=request.url.path,
|
||||
request_id=request_id
|
||||
)
|
||||
|
||||
logger.error(f"Unexpected Error: {str(exc)} (Request ID: {request_id})", exc_info=True)
|
||||
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
content=error_response.model_dump(exclude_none=True)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user