Customization
The idea behind this package is to standardize error responses and make it easier to customize. To accomplish that, the exception handler was rewritten as a class, so it’s easy to subclass and make small customizations. First, we’ll go through a brief description of the flow for generating error response, then we’ll check some customizations that you might want to make.
Exception handling flow
You’re encouraged to read the source code since it’s not that much but here’s a quick overview.
The flow starts with converting known exceptions like
django.core.exceptions.PermissionDenied
anddjango.http.Http404
to DRF exceptions.Any unhandled exception is then converted to an instance of
rest_framework.exceptions.APIException
.Afterwards, the exception data is extracted and formatted, and the error response is generated with the correct headers.
Finally, if the exception is a server error (status code is 5xx) then it is logged and the signal
got_request_exception
is sent out. This helps the django test client or an error monitoring tool like Sentry capture exception details.
Sample customizations
Handle a non-DRF exception
This can be done the same way as what DRF recommends:
Create a new exception class by inheriting from
APIException
and setting thedefault_detail
anddefault_code
attributes.Also, set the
status_code
attribute, but keep in mind that the status code is used to determine the error type. A 4xx status code results in aclient_error
and a 5xx results in aserver_error
.In your view, you can now raise the new exception, and it will be handled appropriately.
Also, you can customize the exception handler instead of raising the new exception in your code:
Assuming the example from DRF docs for a
ServiceUnavailable
exception
from rest_framework.exceptions import APIException
class ServiceUnavailable(APIException):
status_code = 503
default_detail = 'Service temporarily unavailable, try again later.'
default_code = 'service_unavailable'
You need to subclass
drf_standardized_errors.handler.ExceptionHandler
and overrideconvert_known_exceptions
import requests
from drf_standardized_errors.handler import ExceptionHandler
class MyExceptionHandler(ExceptionHandler):
def convert_known_exceptions(self, exc: Exception) -> Exception:
if isinstance(exc, requests.Timeout):
return ServiceUnavailable()
else:
return super().convert_known_exceptions(exc)
Then, update the setting to point to your exception handler class
DRF_STANDARDIZED_ERRORS = {"EXCEPTION_HANDLER_CLASS": "path.to.MyExceptionHandler"}
Change the format of the error response
Let’s say you don’t need to return multiple errors, and you don’t like some key names in the error response: specifically,
you want to change detail
to message
and attr
to field_name
.
You’ll need to subclass ExceptionFormatter
and override format_error_response
.
from drf_standardized_errors.formatter import ExceptionFormatter
from drf_standardized_errors.types import ErrorResponse
class MyExceptionFormatter(ExceptionFormatter):
def format_error_response(self, error_response: ErrorResponse):
error = error_response.errors[0]
return {
"type": error_response.type,
"code": error.code,
"message": error.detail,
"field_name": error.attr
}
Then, update the corresponding setting
DRF_STANDARDIZED_ERRORS = {"EXCEPTION_FORMATTER_CLASS": "path.to.MyExceptionFormatter"}