Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How disable return of HTML error page with django rest framework?

If I have a error outside the libs of DRF, django send back the HTML of the error instead of the proper error response use by DRF.

For example:

@api_view(['POST'])
@permission_classes((IsAuthenticated,))
def downloadData(request):
    print request.POST['tables']

Return the exception MultiValueDictKeyError: "'tables'". And get back the full HTML. How get only the error a JSON?

P.D:

This is the final code:

@api_view(['GET', 'POST'])
def process_exception(request, exception):
    # response = json.dumps({'status': status.HTTP_500_INTERNAL_SERVER_ERROR,
    #                        'message': str(exception)})
    # return HttpResponse(response,
    #                     content_type='application/json; charset=utf-8')
    return Response({
        'error': True,
        'content': unicode(exception)},
        status=status.HTTP_500_INTERNAL_SERVER_ERROR
    )


class ExceptionMiddleware(object):
    def process_exception(self, request, exception):
        # response = json.dumps({'status': status.HTTP_500_INTERNAL_SERVER_ERROR,
        #                        'message': str(exception)})
        # return HttpResponse(response,
        #                     content_type='application/json; charset=utf-8')
        print exception
        return process_exception(request, exception)
like image 432
mamcx Avatar asked Jan 13 '14 20:01

mamcx


People also ask

How do I create a custom exception in Django REST framework?

Custom exception handlingThe exception handler function should either return a Response object, or return None if the exception cannot be handled. If the handler returns None then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.

How improve Django REST API performance?

Django/Python/REST framework is too slow. As this article will argue, the biggest performance gains for Web APIs can be made not by code tweaking, but by proper caching of database lookups, well designed HTTP caching, and running behind a shared server-side cache if possible.

How does pagination work in Django REST framework?

Pagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular APIView , you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the mixins. ListModelMixin and generics.

What is browsable API Django?

The browsable API feature in the Django REST framework generates HTML output for different resources. It facilitates interaction with RESTful web service through any web browser. To enable this feature, we should specify text/html for the Content-Type key in the request header.


3 Answers

One way of returning json would be to catch the exceptions and return proper response (assuming you're using JSONParser as default parser):

from rest_framework.response import Response
from rest_framework import status


@api_view(['POST'])
@permission_classes((IsAuthenticated,))
def downloadData(request):
    try:
        print request.POST['tables']
    except:
        return Response({'error': True, 'content': 'Exception!'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return Response({'error': False})

UPDATE

For global wise use-case the correct idea would be to put the json response in exception middleware.

You can find example in this blog post.

In your case you need to return DRF response, so if any exception gets raised it will end up in the process_exception:

from rest_framework.response import Response


class ExceptionMiddleware(object):

    def process_exception(self, request, exception):
        return Response({'error': True, 'content': exception}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
like image 122
mariodev Avatar answered Oct 19 '22 10:10

mariodev


You can replace the default error handlers by specifying a custom handler in your URLConf as documented here

Something like this:

# In urls.py
handler500 = 'my_app.views.api_500'

and:

# In my_app.views
def api_500(request):
    response = HttpResponse('{"detail":"An Error Occurred"}', content_type="application/json", status=500)
    return response

I hope that helps.

like image 7
Carlton Gibson Avatar answered Oct 19 '22 10:10

Carlton Gibson


As you can see in the documentation.

All you need to do is configure settings.

REST_FRAMEWORK = {
   'DEFAULT_AUTHENTICATION_CLASSES': (
       'rest_framework.authentication.TokenAuthentication',
       'rest_framework.parsers.JSONParser',
    ),
    'EXCEPTION_HANDLER': 'core.views.api_500_handler',
}

And pointing to a view that will recieve (exception, context)

Like this:

from rest_framework.views import exception_handler
...
def api_500_handler(exception, context):
    response = exception_handler(exception, context)
    try:
        detail = response.data['detail']
    except AttributeError:
        detail = exception.message
    response = HttpResponse(
        json.dumps({'detail': detail}),
        content_type="application/json", status=500
    )
    return response

My implementation is like this because if a expected rest framework exception is raised, like a 'exceptions.NotFound', exception.message will be empty. Thats why Im first calling to exception_handler of rest framework. If is an expected exception, I will get its message.

like image 4
Laraconda Avatar answered Oct 19 '22 11:10

Laraconda