问题
I'm starting to dive into DRF a little deeper of late, and I was wondering I would like to start customising the error messaging that gets return via the API for incorrect permissions, I'd like to wrap a little extra detail.
For example, if authentication credentials were not provided for an endpoint that is permission restricted, the API returns:
{
"detail": "Authentication credentials were not provided."
}
Which comes from line 171 from the rest_framework.exceptions
: https://github.com/encode/django-rest-framework/blob/master/rest_framework/exceptions.py. Really, I'd like this to be consistent with the
{
"success": false,
"message": "Authentication credentials were not provided.",
"data": null
}
So, I assume I now need to begin customising my own exceptions.
How best should I go about doing this?
Perhaps it has some tie in with default_error_messages = {}
inside the serializer ...
回答1:
You can override DRF's default exception handler and JSON parser on your settings.py
:
REST_FRAMEWORK = {
...
'EXCEPTION_HANDLER': 'helpers.exceptions.custom_exception_handler',
'DEFAULT_RENDERER_CLASSES': [
'helpers.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
]
}
And then it's just a matter of customizing how to handle your exceptions and how to render the responses:
def custom_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)
# Customize your exception handling here
return response
And you can use the custom JSON renderer in case you need to do any extra formatting on the response, in my case I had to add a "status_code" to the payload:
class JSONRenderer(BaseJsonRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
"""
Render `data` into JSON, returning a bytestring.
"""
<Base code from the original class...>
response = renderer_context.get('response')
if response and 200 <= response.status_code <= 299 and 'status_code' not in response.data:
response.data = Errors.success(response.data)
<Base code from the original class...>
My Errors.success(response.data)
was just a simpler way to merge the success status code to the data.
回答2:
There is a decorator solution that creates custom Response on each type of your exceptions:
# project/api/exceptions.py
from functools import wraps
from rest_framework import status
def handle_exceptions(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except AuthCredentialsError as exc:
return Response(
{"message": exc.message},
status=status.HTTP_405_METHOD_NOT_ALLOWED,
)
return wrapper
# project/api/your_code.py
from project.api.exceptions import handle_exceptions
class SomeViewSet():
@handle_exceptions
def create(self, request, *args, **kwargs):
raise AuthCredentialsError("Authentication credentials were not provided")
来源:https://stackoverflow.com/questions/60317051/drf-customising-exception-messages-from-the-api