Wrapping $.ajax In A Thin “Command” Framework For Backbone Apps

A large number of my recent client applications, built on Backbone, have been using straight jQuery AJAX calls. Sometimes its in combination with Backbone’s persistence method, but other times I end up using AJAX calls in place of Backbone calls.

Non-CRUD-y Apps

Now I don’t think that there’s anything wrong with Backbone’s “save”, “fetch” and “destroy” methods. They’re quite handy, and very well done. The deciding factor in using them is whether or not my application is CRUD-y or not. That is to say, many of my recent apps are taking more of a command approach to user interaction and data updates. Instead of just having simple Create, Read, Update and Delete forms on my apps, I tend to have smaller and more focused commands that are called.

For example, signing a terms of service agreement is a command to sign the agreement, not just a “create” on a resource. Sure, the implementation of that may be a “POST” on a resource location. But that doesn’t mean I need a full Backbone model, or need to think about the signature as a RESTful resource from my JavaScript code.

Executing Commands vs Making AJAX Calls

As a result of all this, I end up using $.ajax a lot… and it’s getting really ugly and obnoxious seeing this all over my code:

var signForm = $.ajax({
  type: "POST",
  url: "/some/form",
  dataType: "JSON",
  data: myData
});

signForm.done(function(response){
  // handle success here
});

signForm.fail(function(response){
  // handle failure here
});

Not only is this ugly when you repeat the $.ajax calls all over the code, but it doesn’t really give the semantic benefit of knowing what the code is really doing. I’m not just making a call across an AJAX connection. I’m trying to execute a command – I’m trying to do something important, and I want my code to reflect that.

So I wrapped up my $.ajax calls in a thin “command” wrapper for my current client app (built with Backbone of course), and ended up with this instead:

// Register a command to use
// -------------------------

Backbone.AjaxCommands.register("signForm", {
  url: "/some/form",
  type: "POST"
});


// somewhere else in the application, use the command
// --------------------------------------------------

var signForm = Backbone.AjaxCommands.get("signForm");

signForm.on("success", function(response){
  // handle success here
});

signForm.on("error", function(response){
  // handle failure here
});

// execute the command and send this data with it
signForm.execute(myData);

Looking at this in comparison to the original $.ajax calls, there are a few less lines of code. Since I have a thin wrapper around the ajax calls and setup, I can make a few assumptions about the calls and provide a little bit of default configuration. 

I can also move the registration of commands somewhere other than the execution of the commands, which is a huge win for readability and organization of the code when it comes time to execute a command.

Of course the handling of events for success, error and completed doesn’t give me any advantage over $.ajax and deferred objects. But the big benefit here and why I don’t mind the thin wraper around the done/fail/always deferred methods, is the semantic value of executing a named command vs configuring an ajax call.

And before you go in to a “semantics are not important” lapse of sanity, just think a little about this line that I once heard from Sharon Cichelli:

Semantics will continue to be important until we learn to communicate in something other than language.

Implementing The Command Structure

This implementation relies on Backbone, Underscore and jQuery, so it’s really only useful in Backbone applications at this point. It’s also important to note that this code is not unit tested at all. I’m using it in my current client application and it is functional for me, but I don’t recommend taking this code as a great implementation, yet. I have plans on turning this into a real plugin, with full testing around it. But like most of my plugins and libraries, it started out as a quick hack in order to get something cleaned up in one of my applications.

// Backbone.AjaxCommands
// ---------------------

Backbone.AjaxCommands = (function (Backbone, $, _) {
    var Commands = {};

    // Private data
    // ------------

    var commandList = {};

    // Public API
    // ----------

    Commands.register = function (commandName, options) {
        commandList[commandName] = options;
    }

    Commands.get = function (commandName) {
        var options = commandList[commandName];
        options = options || {};
        options = _.clone(options);
        var command = new Commands.Command(commandName, options);
        return command;
    };

    // Command Type
    // -------------------

    Commands.Command = function (name, options) {
        this.name = name;
        this.options = options
    };

    _.extend(Commands.Command.prototype, Backbone.Events, {
        execute: function (data) {
            var that = this;

            var config = this.getAjaxConfig(this.options, data);

            this.trigger("before:execute");

            var request = $.ajax(config);
            request.done(function (response) {
                that.trigger("success", response);
            });

            request.fail(function (response) {
                that.trigger("error", response);
            });

            request.always(function (response) {
                that.trigger("complete", response);
            });
        },

        getAjaxConfig: function (options, data) {
            var url = this.getUrl(options, data);

            var ajaxConfig = {
                type: "GET",
                dataType: "JSON",
                url: url
            };

            _.extend(ajaxConfig, options);
            ajaxConfig.data = data;

            return ajaxConfig;
        },

        getUrl: function (options, data) {
            return options.url;
        }
    });

    return Commands;
})(Backbone, $, _);

There ar ea couple of things you’ll want to note in this code:

The call to “register” a command stores the configuration that you provide. The call to “get” a command creates a new command instance and hands it back to you. This is done so that you can have single-use command objects and not have to worry about unbinding events from the command after it has completed. If I held on to a single command instance and just handed that back to you, you would be responsible for unbinding the event handlers after executing the command. 

The wrapper events for “success”, “error”, and “complete” also don’t guarantee to fire if you subscribe to them after the command has been executed. So, it’s important to set up your event handlers before calling .execute on the command object.

I’ve also extracted the “getUrl” method specifically because I need to provide a very custom implementation of this method in my client’s application. I have another plugin that I’m looking at writing, which handles storage and retrieval of URLs in my Backbone apps, including :token replacement in the urls … but that’s another blog post and another plugin to write.

A Timed Polling Mechanism

One of the more interesting things I’m doing with this is using it as a timed polling mechanism. I set up a command and then I wrap the commands “execute” function in another method that I can call from a setTimeout. When the command executes, I check the response. If I find the data I need, I move on. If I don’t find the data I need, I call the wrapper function again, inside of a setTimeout.

var myCommand = Backbone.AjaxCommands.get("myCommand");

var executeCommand = function(){
  myCommand.execute(someData);
};

myCommand.on("success", function(response){
  if (response.someValueImChecking){
    // move on to the next thing, here
  } else {
    // poll again, 1 second from now
    setTimeout(executeCommand, 1000);
  }
});

There’s lot of fun little tricks you can do with a simple object wrapper like this, that would be a little more cumbersome and awkward when directly using $.ajax. 


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in AJAX, Backbone, JQuery, Semantics, Underscore. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Dominik

    Very neat and clean solution. Thank you for sharing.

  • Stof

    This is an interesting read. I also found http://amplifyjs.com/api/request/ which seems to address a similar use case (and more feature AFAICS). What do you think about it ?

    • http://mutedsolutions.com Derick Bailey

      yeah, someone else pointed that out to me on twitter as well. it looks exactly what i’ve done, only with far more features and stability :) definitely something i want to look in to when i have time.

    • http://twitter.com/RomainTribes Romain Tribes

      Damned, it’s great! Thanks for that.

  • supabok

    this is absolutely beautiful! exactly what i was looking for and very clean! reminds me of how commandmaps worked in Robotlegs! keep up the amazing posts!!

  • Trevor Dilley

    So, I’m new to the Backbone world, and I was curious if this would be appropriate for user authentication? In my apps I really just need to send the user/pass combo, but using a jQuery ajax call doesn’t feel right in my gut, but a Backbone model that will be destroyed immediately seems a little much. Is this the healthy balance? Or should I stick with models? Or stop being finicky and use jQuery? MarionetteJS is awesome, thank you for your time!

  • Jon Wingfield

    I really like this solution. I’m starting to run into the same issues with RESTful (ahem, CRUDy) javascript apps :)