15

I am learning Django Rest Framework, and also new to django. I want to return a custom 404 error in json when a client will access a resource which was not found.

My urls.py looks liks this:

urlpatterns = [
    url(r'^mailer/$', views.Mailer.as_view(), name='send-email-to-admin')
]

In which i have only one resource, which can be accessed through URI, http://localhost:8000/mailer/

Now, when a client access any other URI like http://localhost:8000/, API should return a 404-Not Found error like this:

{
    "status_code" : 404
    "error" : "The resource was not found"
}

Please suggest some answer with proper code snippets, if suitable.

Akshay Pratap Singh
  • 3,197
  • 1
  • 24
  • 33
  • i am using `custom_exception_handler` method described in [Django REST framework exceptions](http://www.django-rest-framework.org/api-guide/exceptions/) , to catch exceptions which will raise in function_view or class_views . – Akshay Pratap Singh Jul 13 '15 at 12:41

4 Answers4

22

You are looking for handler404.

Here is my suggestion:

  1. Create a view that should be called if none of the URL patterns match.
  2. Add handler404 = path.to.your.view to your root URLconf.

Here is how it's done:

  1. project.views

    from django.http import JsonResponse
    
    
    def custom404(request, exception=None):
        return JsonResponse({
            'status_code': 404,
            'error': 'The resource was not found'
        })
    
  2. project.urls

    from project.views import custom404
    
    
    handler404 = custom404
    

Read error handling for more details.

Django REST framework exceptions may be useful as well.

JPG
  • 82,442
  • 19
  • 127
  • 206
Ernest
  • 2,799
  • 12
  • 28
  • this solution doesn't work, i did as you described.I also set `DEBUG=False`.But, it return html page, **Not Found The requested URL / was not found on this server.** – Akshay Pratap Singh Jul 13 '15 at 11:55
  • @AkshayPratapSingh Seems like I misunderstood you. Edited my answer and it should work now. – Ernest Jul 13 '15 at 12:35
  • i am using this method to catch rest_framwork view's errors, but it does not catch url route non-matched error, which return 404 error. – Akshay Pratap Singh Jul 13 '15 at 12:39
  • 5
    You should also include status code 404: `JsonResponse({'detail': "The resource was not found", 'status_code': 404}, status=404)` – Heretron Mar 03 '17 at 10:33
6

according to django documentation : Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL. ref: https://docs.djangoproject.com/en/1.8/topics/http/urls/

so you can just add another url in urlpatterns after the one you created and it should match all url patterns and send them to a view that return the 404 code.

i.e :

urlpatterns = [
url(r'^mailer/$', views.Mailer.as_view(), name='send-email-to-admin'),
url(r'^.*/$',views.Error404.as_view(),name='error404')]
sabtikw
  • 67
  • 4
0

@Ernest Ten's answer is correct. However, I would like to add some input if you're using an application that handles both browser page loading and API as call.

I customized the custom404 function to this

def custom404(request, exception=None):
    requested_html = re.search(r'^text/html', request.META.get('HTTP_ACCEPT')) # this means requesting from browser to load html
    api = re.search(r'^/api', request.get_full_path()) # usually, API URLs tend to start with `/api`. Thus this extra check. You can remove this if you want.

    if requested_html and not api:
        return handler404(request, exception) # this will handle error in the default manner

    return JsonResponse({
        'detail': _('Requested API URL not found')
    }, status=404, safe=False)
Koushik Das
  • 9,678
  • 3
  • 51
  • 50
0

update of Ernest Ten answer:

You should also include in urls.py

from django.http import JsonResponse
...other urls...
handler404 = lambda request, exception=None: JsonResponse({'error': '404: The resource was not found'}, status=404)  
suhailvs
  • 20,182
  • 14
  • 100
  • 98