Last Updated: September 27, 2021
· smallhadroncollider

Handling non-200 status codes in Backbone

Many RESTful APIs return non-200 status codes that should be considered a success - e.g. a 201 CREATED. However, Backbone uses the jQuery ajax method and this will treat anything that isn't a 200 code as an error.

The jQuery ajax method does have a statusCode property which lets you setup a switch statement of responses depending on the returned status code. However, even if you set this to call your success callback on a non-200 code the error callback will still be called - which can cause problems in many instances.

However, using a similar method to that discussed in Add a root URL to all Backbone API request we can get around this problem:

define(function () {
    'use strict';

     * Store a version of Backbone.sync to call
     * with modified options
    var backboneSync = Backbone.sync,

         * New error is a currying function. You pass in a method,
         * success function, and error function and it returns a
         * new error function that will call the success function if
         * a 'sucess code' corresponds to the method.
        newError = function (method, success, error) {

            // Each method can have its own specific success code
            var successCodes = {
                    create: 201

            // Return the original error function if no matching 'success code'
            if (!successCodes[method]) {
                return error;

            return function (jqXHR, textStatus, errorThrown) {

                    // If the response is a success code 
                var wasSuccessful = jqXHR.status === successCodes[method],

                // If the status is a 'success code' run the success function
                if (wasSuccessful && _.isFunction(success) ) {

                    // Set the response if there is one
                    response = jqXHR.responseJSON ? jqXHR.responseJSON : {}; 

                    // Call the success function
                    success(response, textStatus, jqXHR);

                // Otherwise run the error as usual
                } else if (_.isFunction(error)) {

                    // Call the original error function
                    error(jqXHR, textStatus, errorThrown);

    // Override Backbone.sync
    Backbone.sync = function (method, model, options) {
        // Set options to error to the new error function
        options.error = newError(method, success, error);

        // Call the stored original Backbone.sync method with the new settings
        backboneSync(method, model, options); 

This new Backbone.sync sets the error callback to a new function which first checks the return status code and calls the success callback if it should be counted as successful. Otherwise it behaves as it would have originally. We can now pass in our usual error and success callbacks and not worry about status code handling.