"""Global exception handlers for the FastAPI application. Maps AppError subclasses and other exceptions to JSON envelope responses. """ import logging import traceback from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse from app.exceptions import AppError logger = logging.getLogger(__name__) def register_exception_handlers(app: FastAPI) -> None: """Register all global exception handlers on the FastAPI app.""" @app.exception_handler(AppError) async def app_error_handler(_request: Request, exc: AppError) -> JSONResponse: return JSONResponse( status_code=exc.status_code, content={ "status": "error", "data": None, "error": exc.message, }, ) @app.exception_handler(RequestValidationError) async def validation_error_handler( _request: Request, exc: RequestValidationError ) -> JSONResponse: details = "; ".join( f"{'.'.join(str(loc) for loc in e['loc'])}: {e['msg']}" for e in exc.errors() ) return JSONResponse( status_code=400, content={ "status": "error", "data": None, "error": f"Validation error: {details}", }, ) @app.exception_handler(Exception) async def unhandled_error_handler( _request: Request, exc: Exception ) -> JSONResponse: logger.error("Unhandled exception:\n%s", traceback.format_exc()) return JSONResponse( status_code=500, content={ "status": "error", "data": None, "error": "Internal server error", }, )