Files
Hotel-Booking/Backend/src/middleware/error_handler.py
2025-11-16 15:59:05 +02:00

128 lines
3.8 KiB
Python

from fastapi import Request, status, HTTPException
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import IntegrityError
from jose.exceptions import JWTError
import os
import traceback
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""
Handle validation errors
"""
errors = []
for error in exc.errors():
field = ".".join(str(loc) for loc in error["loc"] if loc != "body")
errors.append({
"field": field,
"message": error["msg"]
})
# Get the first error message for the main message
first_error = errors[0]["message"] if errors else "Validation error"
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={
"status": "error",
"message": first_error,
"errors": errors
}
)
async def integrity_error_handler(request: Request, exc: IntegrityError):
"""
Handle database integrity errors (unique constraints, etc.)
"""
error_msg = str(exc.orig) if hasattr(exc, 'orig') else str(exc)
# Check for duplicate entry
if "Duplicate entry" in error_msg or "UNIQUE constraint" in error_msg:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={
"status": "error",
"message": "Duplicate entry",
"errors": [{"message": "This record already exists"}]
}
)
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={
"status": "error",
"message": "Database integrity error"
}
)
async def jwt_error_handler(request: Request, exc: JWTError):
"""
Handle JWT errors
"""
return JSONResponse(
status_code=status.HTTP_401_UNAUTHORIZED,
content={
"status": "error",
"message": "Invalid token"
}
)
async def http_exception_handler(request: Request, exc: HTTPException):
"""
Handle HTTPException errors
"""
# If detail is already a dict with status/message, return it directly
if isinstance(exc.detail, dict):
return JSONResponse(
status_code=exc.status_code,
content=exc.detail
)
# Otherwise format as standard error response
return JSONResponse(
status_code=exc.status_code,
content={
"status": "error",
"message": str(exc.detail) if exc.detail else "An error occurred"
}
)
async def general_exception_handler(request: Request, exc: Exception):
"""
Handle all other exceptions
"""
# Log error
print(f"Error: {exc}")
if os.getenv("NODE_ENV") == "development":
traceback.print_exc()
# Handle HTTPException with dict detail
if isinstance(exc, Exception) and hasattr(exc, "status_code"):
status_code = exc.status_code
if hasattr(exc, "detail"):
detail = exc.detail
if isinstance(detail, dict):
# If detail is already a dict with status/message, return it directly
return JSONResponse(status_code=status_code, content=detail)
message = str(detail) if detail else "An error occurred"
else:
message = str(exc) if str(exc) else "Internal server error"
else:
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
message = str(exc) if str(exc) else "Internal server error"
return JSONResponse(
status_code=status_code,
content={
"status": "error",
"message": message,
**({"stack": traceback.format_exc()} if os.getenv("NODE_ENV") == "development" else {})
}
)