""" 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'