error_handlers.py
1 from fastapi import FastAPI, Request 2 from fastapi.responses import JSONResponse 3 import logging 4 import traceback 5 from .response_models import ErrorResponse 6 7 logger = logging.getLogger("cerastes.api") 8 9 class APIError(Exception): 10 """Custom exception for API errors""" 11 def __init__(self, message: str, status_code: int = 400, details: str = None): 12 self.message = message 13 self.status_code = status_code 14 self.details = details 15 super().__init__(self.message) 16 17 def register_exception_handlers(app: FastAPI): 18 """Registers exception handlers for the FastAPI application""" 19 20 @app.exception_handler(APIError) 21 async def handle_api_error(request: Request, exc: APIError): 22 """Handler for custom API errors""" 23 return JSONResponse( 24 status_code=exc.status_code, 25 content=ErrorResponse( 26 error=exc.message, 27 details=exc.details, 28 status_code=exc.status_code 29 ).dict() 30 ) 31 32 @app.exception_handler(404) 33 async def handle_not_found(request: Request, exc: Exception): 34 """Handler for 404 errors""" 35 return JSONResponse( 36 status_code=404, 37 content=ErrorResponse( 38 error="Resource not found", 39 status_code=404 40 ).dict() 41 ) 42 43 @app.exception_handler(405) 44 async def handle_method_not_allowed(request: Request, exc: Exception): 45 """Handler for 405 errors""" 46 return JSONResponse( 47 status_code=405, 48 content=ErrorResponse( 49 error="Method not allowed", 50 status_code=405 51 ).dict() 52 ) 53 54 @app.exception_handler(500) 55 async def handle_server_error(request: Request, exc: Exception): 56 """Handler for server errors""" 57 logger.error(f"Server error: {str(exc)}") 58 logger.error(traceback.format_exc()) 59 return JSONResponse( 60 status_code=500, 61 content=ErrorResponse( 62 error="Internal server error", 63 status_code=500 64 ).dict() 65 ) 66 67 # FastAPI doesn't need an explicit handler for 400 like Flask 68 # as it automatically generates 422 error responses for validation errors