Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django ajax error response best practice

I'm using ajax to improve user experience in my Django project. My concern here is how to respond error to browser properly. As far as I know, I can either:

  1. validate request data piece by piece and guard exception one by one. If something bad happens, raise Http404 or other exception to explicitly announce an error has occurred. Or
  2. just write code without exception handling and suppose it will work. If something bad happens, the uncaught exception would cause an internal server error, which is still an error for the browser

For me, the fisrt method seems more orthodox , as in Python the philosophy of "Explicit is better than Implicit" really counts. But since all sorts of exception checking are removed from the second one, it is cleaner, less fragmented and more readable.

I'm using jQuery to handle ajax request/response and both methods seem working. My questions are:

  1. Are both methods acceptable?
  2. Will the second method fail for other Javascript libraries?
  3. What is the best practice for this?

PS. I do do essential data validation. Please do not stray the topic for that. :)

like image 323
kavinyao Avatar asked Mar 21 '12 01:03

kavinyao


2 Answers

If you return a response with a status code of 4xx or 5xx this is a an error and will trigger jQueries error handler. While it is certainly possible to simple return status 200 every time and use a "error" field in the JSON response (like suggested by dm03514) this is bad for two reasons:

  1. It violates good HTTP practice. There is a reason why there are plenty of error-codes defined

  2. You can't use the fact that jQuery already has a error-Handler that lets you separate normal behavior from error handling.

Most of the time the error response will be much different from the non-error response So it simply makes no sense to put the handling of this messages in one piece of JS code. So, to sum things up, use a JSON response with status 200 for your normal responses and return a (appropriate!) 4xx/5xx response for errors. These can carry JSON payload, too, so your server side can add additional details about the error.

like image 134
Martin Thurau Avatar answered Nov 10 '22 11:11

Martin Thurau


In my opinion:

  1. the second method is not acceptable.
  2. it will not failed since server will still send out a http response.
  3. Let me tell you what I do in my projects:

when my project starts, I always pre-add a module named errors in top of folder structure, firstly, I will write a base Exception class which inherits from Exception, then write out some common Exception classes like ObjectNotFound, ValidationError from my experience. When I think there should raise an exception in my code, I will use exceptions from this module, and when I find new kind of exception need to be handled, I will write a new exception in it.

Then it's the work for how to handle them. As you are using Django, it very easy to catch exceptions through a middleware, you can write something like this:

from youproject import errors

# categorize your exceptions
400_ERRORS = (errors.ValidationError, errors.ParametersMissing, )
403_ERRORS = (errors.AuthenticationError, )
404_ERRORS = (errors.ObjectNotFound, errors.ResourceNotExist, )

class ExceptionHandleMiddleware(object):
    def process_exception(self, request, e):
        # set status_code by category of the exception you caught
        if isinstance(e, 400_ERRORS):
            status_code = 400
        elif isinstance(e, 403_ERRORS):
            status_code = 403
        elif isinstance(e, 404_ERRORS):
            status_code = 404
        else:
            # if the exception not belone to any one you expected,
            # or you just want the response to be 500
            status_code = 500
            # you can do something like write an error log or send report mail here
            logging.error(e)

        response_dict = {
            'status': 'error',
            # the format of error message determined by you base exception class
            'msg': str(e)
        }
        if settings.debug:
            # you can even get the traceback infomation when you are in debug mode
            response_dict['traceback'] = traceback.format_exc()

        # set header and return the response
        ....

The code above is a summary of how I do exception handle in my projects, in general, it's about accurate exception controling, proper exception categorizing, and of course 'Explicit is better than Implicit' philosophy.

===UPDATE=== When it comes to how to deal with the corresponding responses in ajax, you can use the new feature in jquery1.5 statusCode:

$.ajax({
  statusCode: {
    404: function() {
      alert('page not found');
    }
  }
});

from jquery documentation:

A map of numeric HTTP codes and functions to be called when the response has the corresponding code. For example, the following will alert when the response status is a 404

like image 35
Reorx Avatar answered Nov 10 '22 11:11

Reorx