arbret/backend/exceptions.py

85 lines
2.2 KiB
Python
Raw Normal View History

2025-12-25 00:59:57 +01:00
"""Standardized API exception classes for consistent error responses.
Note: These exceptions use string detail for backward compatibility with existing tests.
Future refactoring could standardize on structured error responses.
"""
from fastapi import HTTPException, status
class APIError(HTTPException):
"""Base API error with consistent structure.
Uses string detail for backward compatibility with existing tests.
"""
def __init__(
self,
status_code: int,
message: str,
):
super().__init__(status_code=status_code, detail=message)
class NotFoundError(APIError):
"""Resource not found error (404)."""
def __init__(self, resource: str):
super().__init__(
status_code=status.HTTP_404_NOT_FOUND,
message=f"{resource} not found",
)
class ConflictError(APIError):
"""Conflict error (409)."""
def __init__(self, message: str):
super().__init__(
status_code=status.HTTP_409_CONFLICT,
message=message,
)
class BadRequestError(APIError):
"""Bad request error (400)."""
def __init__(self, message: str):
super().__init__(
status_code=status.HTTP_400_BAD_REQUEST,
message=message,
)
class UnauthorizedError(APIError):
"""Unauthorized error (401)."""
def __init__(self, message: str = "Not authenticated"):
super().__init__(
status_code=status.HTTP_401_UNAUTHORIZED,
message=message,
)
2025-12-25 00:59:57 +01:00
class ServiceUnavailableError(APIError):
"""Service unavailable error (503)."""
def __init__(self, message: str):
super().__init__(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
message=message,
)
class ValidationError(HTTPException):
"""Validation error (422) with field-specific errors."""
def __init__(self, message: str, field_errors: dict[str, str] | None = None):
detail: dict[str, str | dict[str, str]] = {"message": message}
if field_errors:
detail["field_errors"] = field_errors
super().__init__(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=detail,
)