Thoughts on developing resilient Ajax code (Part 1)

This sunny afternoon I was writing an ASP.net controller method to return JSON data from a calculation service.

As we all know things can always go wrong in code (and not necessarily just because I wrote it!) and this got me thinking about best practice when making and handling Ajax calls.

There are a number of issues we need to think about if we want to avoid the terrible situation of our users not being able to buy 1000’s of those new silver cat widgets we have been flogging because a vital Ajax shopping basket related request failed such as:

  • Errors encoding our request & its body before we have even sent it – maybe the users entered something dumb (did you let them? or are they a hacker and up to no good)
  • Timeout’s & a user’s session ending – e.g. the user felt the need for coffee and got caught up in a discussion about how would win in a chainsaw fight between the neighbours and home & away cast (dodgey Australian tv series)
  • Server side errors (you probably screwed something up)
  • Issues reading/decoding the response (see above)
  • Transient network conditions – those times things fail and no one’s really er sure why as it works if you try again

Mobile web applications in particular are very vulnerable to transient network conditions. I started (and forgot about) building a wrapper to retry requests which ill get round to looking at again sooner or later (https://github.com/alexmackey/retryajax).

Ok so what do we mean by resiliency?

Well to me in this context it means:

  • Having a service that works almost always
  • Something that can recovers from temporary errors such as timeouts without crashing the whole application
  • ..or failing the ability to recover provides sensible information about what might have gone wrong (and if there’s anything a user can do to remedy/help)
  • Handles a decent number of requests
  • Ideally it would also be really really nice if we had some info about what went wrong and if something went wrong so we could fix it

As you can see there are a decent number of issues here and some of these aren’t as straightforward to solve as they  may first appear so I am going to first look at how to return a valid/invalid response at a high level.

I guess there are three main (and combination of) ways to handle this:

  • Set a relevant HTTP status code on the response and potentially populate the body with some details of the error
  • Return a standard HTTP 200 everything’s peachy response and set a status code in the responses (true/false & success/fail seem in pretty common usage)
  • Don’t do anything

A lot of websites actually do the third option and assume that every AJAX call is going to work out fine and dandy (have a look in your browsers network tools & JavaScript console next time you are bored). I think we can all agree isn’t a good idea unless it’s a particularly trivial request.

Anyway since there were a variety of methods in use I wondered if people had a preference for how this was done so put this out to Twitter:

“If you were calling service to get JSON formatted data & error occurred would you prefer http error code to be set or 200 & error in json?”

Of course this being Twitter and the fact that it’s always dangerous to ask for peoples opinion I got a mix of useful and not so useful replies including:

The general consensus was that appropriate Http status code’s should be set before returning the response.

Why?

Well this approach has a number of advantages such as:

  • Http status code integrate nicely with various JavaScript libraries error handling routines like jQuery’s global .ajaxError and error methods
  • Its potentially easier for people to integrate with our service as its nice, descriptive & potentially RESTful in nature
  • Its easy to spot error status codes in Fiddler/browser tools/logs which helps if something goes wrong

And I would agree setting a status code is probably the best approach.

Can this lead to some ambiguity?

Let’s say we had a method that allows the retrieval of an individual entity by Id. We call it and get a  404 Not found – is my requested entity missing or do I have the wrong URI?

Or how about  we get a 401 (Unauthorized) were we unauthorized to call the Api or have we screwed up our security configuration?

Well I don’t think these are going to be too tricky to deal with as we can always include additional information in our response, status codes are a pretty accepted way of doing things and I think the benefits outweigh any confusion so let’s stick with using Http Status codes.

Now let’s look at how to set these codes in ASP.net & ASP.net MVC.

ASP.net MVC & ASP.net offer numerous ways (ASP.net Web API has more) to set the HttpStatusCode of a response (note there is a nice enum of the various codes called HttpStatusCode) including:

Response.StatusCode = 404;

throw new HttpException(404, “Um where’s it gone”);

return HttpNotFound();

return new HttpStatusCodeResult(404);

There are however a couple of potential pitfalls to watch out for when using with ASP.net & ASP.net MVC as certain error codes will trigger behaviour in IIS/ASP.net MVC framework which might not give you what you would expect:

  • Returning 404’s (not found) will kick in IIS’s 404 page without disabling this Response.TrySkipIisCustomErrors = true;
  • Http 401’s (unauthorized) depending on your authentication setup will send you off to the login page (aspnet.suppressformsredirect NuGet package apparently will prevent this)

Well none of these are too tricky to deal with so I am not overly concerned by these and they shouldn’t stop you from using HttpStatusCode to indicate the status of your request.

So in conclusion:

  • Use Http status codes they work well with libaries, help debugging and are an accepted way of doing things
  • Be consistent – a mix of approaches is really bad news

Next up – implementing this in ASP.net MVC..

Advertisements

3 thoughts on “Thoughts on developing resilient Ajax code (Part 1)

  1. We had pretty much the same discussion at my workplace, and reached the same conclusion for the same reasons. Good to know others are on the same wavelength.

  2. Agree on the use of status codes, however if you are using JSONP in your client, status would only help a developer diagnosing an error. Because the response loads by adding script tag to the dom, your Js code typically has no idea if the call failed or why. You need to include a status in the response data, and avoid the normal IIS / browser meddling with 200 ok in the real status.

Comments are closed.