"""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) )