Patrick Altman

I am the VP of Engineering at Eldarion, Co-Founder of Amino Software, and a Mentor at jumpstart foundry.

I am equally passionate about writing code as I am about building businesses.

You really should

Posted On

April 30, 2012, 7:51 a.m.

Tags

Do you have an iOS or web application that you'd like help with?

Eldarion offers lean coaching, software development, code reviews, and in some cases staff augmentation.

Give me a call at 615-300-2930 or send us an email and let's see how we can help you.

This site is hosted on

You should consider it for your Django/Python web hosting as well!

Integration of Backbone.js with Tastypie

I recently started learning more about backbone.js as a way to create richer app-like experiences on the web without the kludge that results from creating DOM elements in jQuery. I bought all three PeepCodes on the topic and have watched them all now a few times (they are densely packed with good material).

PeepCode Screencasts:

We have been doing more and more of not only these richer app-like user interfaces on the web, but also API-backed iOS apps that extend the reach and functionality of the web application. Therefore, something like backbone.js just makes sense as we can share the API for both the web application as well as the iOS app.

When I first got started, it became obvious to me pretty quickly that backbone.js shipped with a lot of default assumptions about how the REST API worked (predicted url paths, data structures, and so on).

I am a big fan of Tastypie, in fact, all of us at Eldarion are. It's dead simple to extend and customize, enabling us to quickly and easily add APIs to sites.

There were a couple of small things that didn't work out of the box with Tastypie and so after some searching I found a js shim that fixed that (well kind of, there were a few bugs related to creating objects), called backbone-tastypie.js.

I didn't feel up to fixing the bugs in the backbone-tastypie. In addition, I wanted to get rid of depending on an extra third party javascript include. The things that were missing in terms of causing an incompatibility between backbone.js ans Tastypie were so minor, it didn't seem worth it to have this shim. Being a Python developer more than a javascript developer, I wanted to customize how things in Python.

I was able to do this with one simple base class that all my ModelResource classes implement:

class BackboneCompatibleResource(ModelResource):

    class Meta:
        always_return_data = True

    def alter_list_data_to_serialize(self, request, data):
        return data["objects"]

With this and the setting of always_return_data = True in the Meta class of each ModelResource, everything was working great without the need for the buggy js shim.

I tweeted a pronouncement of solving this great and mysterious problems and it actually garnered a number of replies from people wanting to know how I solved such a problem. These were replies from people that I respect a great deal and therefore caused me to question myself. Did I really solve this "problem" so easily? What was I missing? There had to be something I was missing.

Then I got a message from Daniel Lindsley, author of Tastypie (as well as many other wonderful open source apps). Turns out, while what I had done will work, it does cause you miss out on the list metadata that Tastypie provides. Without this metadata, you have to make non-obvious assumptions about how the API works.

Daniel offered a solution (in javascript) that removed the need for the shim but actually added that extra bit of meta data information to the backbone Collection objects which can be used to facilitate smarter paging of data through the API. In addition, there is a bit of code to make sure the URLs have slashes appended to the URL therefore avoiding the need for a redirect on every API call.

window.TastypieModel = Backbone.Model.extend({
    base_url: function() {
      var temp_url = Backbone.Model.prototype.url.call(this);
      return (temp_url.charAt(temp_url.length - 1) == '/' ? temp_url : temp_url+'/');
    },

    url: function() {
      return this.base_url();
    }
});

window.TastypieCollection = Backbone.Collection.extend({
    parse: function(response) {
        this.recent_meta = response.meta || {};
        return response.objects || response;
    }
});

Now I just add this bit of javascript to my site's JS and extend TastypieModel and TastypieCollection and everything magically just works. Note, you still need to set always_return_data = True on every ModelResource that you plan to handle POST methods for creating objects. I much prefer to have these additional classes than something that extended/modified standard bootstrap.

I am still learning a ton, but having fun in the process. If you see that I am doing somethign wrong here, please don't hesitate to point it out to me—I welcome the criticism/correction.

Feedback and Commentary

blog comments powered by Disqus