129 lines
4.1 KiB
Python
129 lines
4.1 KiB
Python
"""
|
|
Custom exception handlers for the API.
|
|
"""
|
|
from rest_framework.views import exception_handler
|
|
from rest_framework.response import Response
|
|
from rest_framework import status
|
|
from django.core.exceptions import ValidationError
|
|
from django.db import IntegrityError
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def custom_exception_handler(exc, context):
|
|
"""
|
|
Custom exception handler for API responses.
|
|
"""
|
|
# Call REST framework's default exception handler first
|
|
response = exception_handler(exc, context)
|
|
|
|
if response is not None:
|
|
custom_response_data = {
|
|
'error': True,
|
|
'message': 'An error occurred',
|
|
'details': response.data,
|
|
'status_code': response.status_code,
|
|
}
|
|
|
|
# Handle specific error types
|
|
if isinstance(exc, ValidationError):
|
|
custom_response_data['message'] = 'Validation error'
|
|
custom_response_data['details'] = exc.message_dict if hasattr(exc, 'message_dict') else str(exc)
|
|
|
|
elif isinstance(exc, IntegrityError):
|
|
custom_response_data['message'] = 'Data integrity error'
|
|
custom_response_data['details'] = 'The operation could not be completed due to data constraints'
|
|
response.status_code = status.HTTP_400_BAD_REQUEST
|
|
|
|
elif response.status_code == status.HTTP_401_UNAUTHORIZED:
|
|
custom_response_data['message'] = 'Authentication required'
|
|
custom_response_data['details'] = 'Please provide valid authentication credentials'
|
|
|
|
elif response.status_code == status.HTTP_403_FORBIDDEN:
|
|
custom_response_data['message'] = 'Access denied'
|
|
custom_response_data['details'] = 'You do not have permission to perform this action'
|
|
|
|
elif response.status_code == status.HTTP_404_NOT_FOUND:
|
|
custom_response_data['message'] = 'Resource not found'
|
|
custom_response_data['details'] = 'The requested resource could not be found'
|
|
|
|
elif response.status_code == status.HTTP_429_TOO_MANY_REQUESTS:
|
|
custom_response_data['message'] = 'Rate limit exceeded'
|
|
custom_response_data['details'] = 'Too many requests. Please try again later.'
|
|
|
|
elif response.status_code >= 500:
|
|
custom_response_data['message'] = 'Internal server error'
|
|
custom_response_data['details'] = 'An unexpected error occurred. Please try again later.'
|
|
# Log server errors
|
|
logger.error(f"Server error: {exc}", exc_info=True)
|
|
|
|
response.data = custom_response_data
|
|
|
|
return response
|
|
|
|
|
|
class APIException(Exception):
|
|
"""
|
|
Base exception for API errors.
|
|
"""
|
|
status_code = status.HTTP_400_BAD_REQUEST
|
|
message = 'An error occurred'
|
|
|
|
def __init__(self, message=None, status_code=None, details=None):
|
|
if message:
|
|
self.message = message
|
|
if status_code:
|
|
self.status_code = status_code
|
|
self.details = details or {}
|
|
super().__init__(self.message)
|
|
|
|
|
|
class ValidationException(APIException):
|
|
"""
|
|
Exception for validation errors.
|
|
"""
|
|
status_code = status.HTTP_400_BAD_REQUEST
|
|
message = 'Validation error'
|
|
|
|
|
|
class AuthenticationException(APIException):
|
|
"""
|
|
Exception for authentication errors.
|
|
"""
|
|
status_code = status.HTTP_401_UNAUTHORIZED
|
|
message = 'Authentication required'
|
|
|
|
|
|
class PermissionException(APIException):
|
|
"""
|
|
Exception for permission errors.
|
|
"""
|
|
status_code = status.HTTP_403_FORBIDDEN
|
|
message = 'Access denied'
|
|
|
|
|
|
class NotFoundException(APIException):
|
|
"""
|
|
Exception for not found errors.
|
|
"""
|
|
status_code = status.HTTP_404_NOT_FOUND
|
|
message = 'Resource not found'
|
|
|
|
|
|
class RateLimitException(APIException):
|
|
"""
|
|
Exception for rate limit errors.
|
|
"""
|
|
status_code = status.HTTP_429_TOO_MANY_REQUESTS
|
|
message = 'Rate limit exceeded'
|
|
|
|
|
|
class BusinessLogicException(APIException):
|
|
"""
|
|
Exception for business logic errors.
|
|
"""
|
|
status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
|
|
message = 'Business logic error'
|
|
|