71 lines
1.9 KiB
Python
71 lines
1.9 KiB
Python
"""Custom exceptions for the API."""
|
|
|
|
from fastapi import HTTPException, status
|
|
|
|
|
|
class APIException(HTTPException):
|
|
"""Base API exception with structured error format."""
|
|
|
|
def __init__(
|
|
self,
|
|
status_code: int,
|
|
message: str,
|
|
field: str = None,
|
|
code: str = None,
|
|
detail: str = None
|
|
):
|
|
self.message = message
|
|
self.field = field
|
|
self.code = code or self._get_default_code(status_code)
|
|
super().__init__(status_code=status_code, detail=detail or message)
|
|
|
|
def _get_default_code(self, status_code: int) -> str:
|
|
"""Get default error code based on status code."""
|
|
codes = {
|
|
400: "BAD_REQUEST",
|
|
401: "UNAUTHORIZED",
|
|
403: "FORBIDDEN",
|
|
404: "NOT_FOUND",
|
|
409: "CONFLICT",
|
|
422: "VALIDATION_ERROR",
|
|
429: "RATE_LIMIT_EXCEEDED",
|
|
500: "INTERNAL_SERVER_ERROR",
|
|
503: "SERVICE_UNAVAILABLE"
|
|
}
|
|
return codes.get(status_code, "UNKNOWN_ERROR")
|
|
|
|
|
|
class ValidationError(APIException):
|
|
"""Validation error exception."""
|
|
|
|
def __init__(self, message: str, field: str = None):
|
|
super().__init__(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
message=message,
|
|
field=field,
|
|
code="VALIDATION_ERROR"
|
|
)
|
|
|
|
|
|
class NotFoundError(APIException):
|
|
"""Resource not found exception."""
|
|
|
|
def __init__(self, message: str = "Resource not found"):
|
|
super().__init__(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
message=message,
|
|
code="NOT_FOUND"
|
|
)
|
|
|
|
|
|
class RateLimitError(APIException):
|
|
"""Rate limit exceeded exception."""
|
|
|
|
def __init__(self, message: str = "Rate limit exceeded"):
|
|
super().__init__(
|
|
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
|
message=message,
|
|
code="RATE_LIMIT_EXCEEDED"
|
|
)
|
|
|