Include request data in Django Rest Framework custom exception handler response data

4k views Asked by At

Tech used:

http://www.django-rest-framework.org

Exceptions: http://www.django-rest-framework.org/api-guide/exceptions/

Included rest_framework default example in custom exceptions.py file:

from rest_framework.views import exception_handler

import sys

def custom_exception_handler(exc, context=None):

    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc)

    # Now add the HTTP status code to the response and rename detail to error
    if response is not None:
        response.data['status_code'] = response.status_code
        response.data['request'] = request
        response.data['error'] = response.data.get('detail')
        del response.data['detail']

    return response

This sends basic error info like "Http404" etc, but no request data, like ip address, etc.

Best way to add my request into the response? Thanks in advance.

UPDATE (and solved):

So, I was initially trying to solve this using DjangoRestFramework 2.4.x, but that version doesn't have the request or context data options for the custom exception handler. Upgrading to 3.1.3 made it easy to add the data into the response. New code now looks like this (using version 3.1.3):

def custom_exception_handler(exc, request):

# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, request)

# Send error to rollbar
rollbar.report_exc_info(sys.exc_info(), request)

# Now add the HTTP status code to the response and rename detail to error
if response is not None:
    response.data['status_code'] = response.status_code
    response.data['error'] = response.data.get('detail')
    del response.data['detail']

return response
1

There are 1 answers

10
Rahul Gupta On

This should work for your case.

from rest_framework.views import exception_handler

import sys

def custom_exception_handler(exc, context=None):

    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc)

    # Now add the HTTP status code to the response and rename detail to error
    if response is not None:
        response.data['status_code'] = response.status_code
        response.data['request'] = context['request']
        response.data['error'] = response.data.get('detail')
        del response.data['detail']

    return response

You can access the request from the context passed to the custom_exception_handler. This was added in DRF 3.1.0. Also refer this issue where it was resolved.

If you are using DRF<3.1, there would be no request in the context of exception handler. You can upgrade to DRF 3.1.3(latest version in PyPI) and then easily access the request in context.

Taken from DRF 3.1.1 source code:

def get_exception_handler_context(self):
    """
    Returns a dict that is passed through to EXCEPTION_HANDLER,
    as the `context` argument.
    """
    return {
        'view': self,
        'args': getattr(self, 'args', ()),
        'kwargs': getattr(self, 'kwargs', {}),
        'request': getattr(self, 'request', None)
    }

Also, you need to configure the exception handler in your settings.py file.

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}

If it is not specified, the 'EXCEPTION_HANDLER' setting defaults to the standard exception handler provided by REST framework:

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}

Note:

Exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the HTTP_400_BAD_REQUEST responses that are returned by the generic views when serializer validation fails.