11import logging
2- from typing import Dict , Union
32
4- from django .core .exceptions import (
5- PermissionDenied ,
6- ValidationError as DjangoValidationError ,
7- )
8- from django .http import Http404
93from rest_framework import exceptions
104from rest_framework .response import Response
11- from rest_framework .serializers import as_serializer_error
125from rest_framework .views import set_rollback
136
14- from drf_simple_api_errors import formatter
7+ from drf_simple_api_errors import formatter , handlers
158from drf_simple_api_errors .exceptions import ServerError
16- from drf_simple_api_errors .settings import api_settings
179from drf_simple_api_errors .types import ExceptionHandlerContext
1810
1911logger = logging .getLogger (__name__ )
@@ -41,22 +33,22 @@ def exception_handler(exc: Exception, context: ExceptionHandlerContext) -> Respo
4133 # This allows for custom exception handling logic.
4234 # If other kinds of exceptions are raised and should be handled,
4335 # they can be added to the EXTRA_HANDLERS setting.
44- _apply_extra_handlers (exc )
36+ handlers . apply_extra_handlers (exc )
4537
4638 # If the exception is not an instance of APIException, we can try to convert it
4739 # to DRF APIException if it's a Django exception.
48- exc = _convert_django_exc_to_drf_api_exc (exc )
40+ exc = handlers . convert_django_exc_to_drf_api_exc (exc )
4941 # If the exception is still not an instance of APIException, thus could be
5042 # converted to one, we cannot handle it.
5143 # This will result in a 500 error response without any detail.
5244 # This is because it's not good practice to expose the details of
5345 # unhandled exceptions to the client.
5446 if not isinstance (exc , exceptions .APIException ):
55- logger .debug ("Server error" , exc_info = True )
47+ logger .info ("Server error (500) from unexpected exception. " , exc_info = True )
5648 return ServerError
5749
5850 # Get the API response headers from the exception.
59- headers = _get_response_headers (exc )
51+ headers = handlers . get_response_headers (exc )
6052 # Get the API response data from the exception.
6153 # If the exception is an instance of APIException, we can handle it and
6254 # will format it to a structured API response data.
@@ -65,61 +57,3 @@ def exception_handler(exc: Exception, context: ExceptionHandlerContext) -> Respo
6557 set_rollback ()
6658 # Finally, return the API response \(◕ ◡ ◕\)
6759 return Response (data , status = exc .status_code , headers = headers )
68-
69-
70- def _apply_extra_handlers (exc : Exception ):
71- """
72- Apply any extra exception handlers defined in the settings.
73-
74- Args:
75- exc (Exception): The exception to handle.
76- """
77- extra_handlers = api_settings .EXTRA_HANDLERS
78- if extra_handlers :
79- for handler in extra_handlers :
80- handler (exc )
81-
82-
83- def _convert_django_exc_to_drf_api_exc (
84- exc : Exception ,
85- ) -> Union [exceptions .APIException , Exception ]:
86- """
87- Convert Django exceptions to DRF APIException, if possible.
88-
89- Args:
90- exc (Exception): The exception to convert.
91-
92- Returns:
93- exceptions.APIException | Exception: The converted exception or the original.
94- """
95- if isinstance (exc , DjangoValidationError ):
96- return exceptions .ValidationError (as_serializer_error (exc ))
97-
98- if isinstance (exc , Http404 ):
99- return exceptions .NotFound ()
100-
101- if isinstance (exc , PermissionDenied ):
102- return exceptions .PermissionDenied ()
103-
104- return exc
105-
106-
107- def _get_response_headers (exc : exceptions .APIException ) -> Dict :
108- """
109- Get the response headers for the given exception.
110-
111- Args:
112- exc (exceptions.APIException): The exception to get headers for.
113-
114- Returns:
115- dict: A dictionary containing the response headers.
116- """
117- # This is from DRF's default exception handler.
118- # https://github.com/encode/django-rest-framework/blob/48a21aa0eb3a95d32456c2a927eff9552a04231e/rest_framework/views.py#L87-L91
119- headers = {}
120- if getattr (exc , "auth_header" , None ):
121- headers ["WWW-Authenticate" ] = exc .auth_header
122- if getattr (exc , "wait" , None ):
123- headers ["Retry-After" ] = "%d" % exc .wait
124-
125- return headers
0 commit comments