Files
gh-greyhaven-ai-claude-code…/skills/api-design-standards/templates/error-handler.py
2025-11-29 18:29:15 +08:00

116 lines
3.4 KiB
Python

# Grey Haven Studio - Error Handler Template
# Add this to app/core/exceptions.py
from fastapi import HTTPException, Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import IntegrityError, OperationalError
import logging
logger = logging.getLogger(__name__)
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
"""Handle HTTPException with standard error format."""
logger.warning(f"HTTP exception: {exc.status_code} - {exc.detail}")
return JSONResponse(
status_code=exc.status_code,
content={
"error": exc.detail,
"status_code": exc.status_code,
},
headers=exc.headers,
)
async def validation_exception_handler(
request: Request, exc: RequestValidationError
) -> JSONResponse:
"""Handle Pydantic validation errors."""
errors = []
for error in exc.errors():
field_path = ".".join(str(loc) for loc in error["loc"] if loc != "body")
errors.append(
{
"field": field_path if field_path else None,
"message": error["msg"],
"code": error["type"],
}
)
logger.warning(f"Validation error: {errors}")
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={
"error": "Validation error",
"detail": errors,
"status_code": 422,
},
)
async def integrity_error_handler(
request: Request, exc: IntegrityError
) -> JSONResponse:
"""Handle database integrity errors."""
logger.error(f"Integrity error: {exc}")
error_detail = "A resource with this unique value already exists"
if "foreign key" in str(exc).lower():
error_detail = "Referenced resource does not exist"
return JSONResponse(
status_code=status.HTTP_409_CONFLICT,
content={
"error": error_detail,
"status_code": 409,
},
)
async def operational_error_handler(
request: Request, exc: OperationalError
) -> JSONResponse:
"""Handle database operational errors."""
logger.error(f"Database operational error: {exc}")
return JSONResponse(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
content={
"error": "Service temporarily unavailable",
"detail": "Database connection error. Please try again later.",
"status_code": 503,
},
)
async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""Catch-all handler for unexpected exceptions."""
logger.exception(f"Unhandled exception: {exc}")
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={
"error": "Internal server error",
"status_code": 500,
},
)
# Register in main.py:
# from app.core.exceptions import (
# http_exception_handler,
# validation_exception_handler,
# integrity_error_handler,
# operational_error_handler,
# generic_exception_handler,
# )
#
# app.add_exception_handler(HTTPException, http_exception_handler)
# app.add_exception_handler(RequestValidationError, validation_exception_handler)
# app.add_exception_handler(IntegrityError, integrity_error_handler)
# app.add_exception_handler(OperationalError, operational_error_handler)
# app.add_exception_handler(Exception, generic_exception_handler)