DRF: Customising Exception Messages from the API

故事扮演 提交于 2020-04-10 06:35:32

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!