drf-standardized-errors
drf-standardized-errors copied to clipboard
Add support for adding 'extra details' (meta) in error response
Add support for adding 'extra details' (meta) in error response
Example: We have a REST API 'add-employee'. It adds employee with given information into Django Database. It checks if employee already exists with "mobile number" and returns error: "Employee already exists".
When returning "Employee already exists" error, we also want to return "Existing Employee Details" to client in this error response. This can be useful for client (frontend) to show it to user.
Can we add support to return some "extra_details" or "meta" information along with error response?
If we already support this, then please let me know how to do this. I was not able to figure this out from docs/my experiments.
@sachingaikwad123, this is already possible as long as this is not a validation error raised in a serializer.
First, define your custom exception
from rest_framework.exceptions import APIException
class ObjectAlreadyExistsError(APIException):
status_code = 409
default_detail = 'Object already exists'
default_code = 'conflict'
def __init__(self, detail=None, code=None, extra_data=None):
self.extra_data = extra_data
super().__init__(detail, code)
create a custom exception formatter and update your settings to point to the new exception formatter
from drf_standardized_errors.formatter import ExceptionFormatter
class CustomExceptionFormatter(ExceptionFormatter):
def format_error_response(self, error_response: ErrorResponse):
resp = super().format_error_response(error_response)
if isinstance(self.exc, ObjectAlreadyExistsError):
resp["extra_data"] = self.exc.extra_data
return resp
raise the exception in your code
class EmployeeCreateView(CreateAPIView):
...
def create(self, request, *args, **kwargs):
...
if some_condition:
raise ObjectAlreadyExistsError("Employee Already Exists", extra_data={"id":1, "name": "John Doe"})
...
Then the API response should look like
{
"type": "client_error",
"errors": [
{
"code": "conflict",
"detail": "Employee Already Exists",
"attr": null
}
],
"extra_data": {"id": 1, "name": "John Doe"}
}
Note that attaching extra data to ValidationErrors or its subclasses raised in a serializer doesn't work because DRF creates new ValidationError instances when they are raised. See here and here
Excellent. I could not figure this out myself. I was raising ValidationError manually and was running into not expected 'errors' dict in response.
Thanks for your detailed response. I will try this out with a custom exception class.
It would be nice to have it in the library somehow... For instance agree on some 'attribute' which will be propagated as metadata. Current suggestion is amazing, but the problem - how to add this metadata to validation errors and all other errors?
To add metadata to validation-errors-raised-outside-the-serializer and other errors, a similar approach should work
class EmployeeCreateView(CreateAPIView):
...
def create(self, request, *args, **kwargs):
...
if some_condition:
exc = ValidationError("Employee Already Exists")
exc.metadata = {"id":1, "name": "John Doe"}
raise exc
...
then in the formatter class, get the data from the metadata attribute
from drf_standardized_errors.formatter import ExceptionFormatter
class CustomExceptionFormatter(ExceptionFormatter):
def format_error_response(self, error_response: ErrorResponse):
resp = super().format_error_response(error_response)
resp["metadata"] = getattr(self.exc, "metadata", None)
return resp
For validation errors raised inside a serializer, you cannot pass metadata from the serializer up to the exception handler due to how drf deals with those specific errors. What you can do instead is either raise another type of exception in the serializer or move the validation outside of the serializer (to the view for example.)