Codiqa is the fastest mobile prototyping tool around. Learn more
0 Flares 0 Flares ×

A few months ago I gave a small presentation at MadJS about how we use Backbone.js to build our jQuery Mobile drag-and-drop interface builder, Codiqa. For this series of posts, I’d like to expand on that presentation and explore concrete examples from the Codiqa codebase of how we use Backbone and why we absolutely love it. This first post will detail our API and how we use Backbone to quickly interact with it.

Architecture Summary

Codiqa is, at its core, an app building application. Thus, there is a core model that makes up this application: an “App”. There are also some other models, like Themes, Assets (images, media), and App Versions.

Apps can be saved, loaded, modified, or deleted.

API Driven Development

We started developing our backend service as a simple REST API. This means, whenever we need to expose or modify a resource, we create an API URL that can handle the resource type. This is a great way to build an API for future public use, but to also have a clearly defined method of exposing and interacting with resources on the server. This API is not open to public use officially, but we’ve added a version number into the URL to make sure we can make breaking changes in new versions in case anyone is actually using it.

Here is the API URL that defines one app with the id of “1″:

/api/v1/user/app/1

We can then send GET, POST, PUT, and DELETE requests to this URL to modify the app. All operations respond with JSON, and use HTTP response codes extensively. For example, if you try to DELETE an app that you do not own, or if you are not logged in, you will get an HTTP 403 response, denying you.

Wrap the API

Now that we have our API defined, it’s a snap to wrap the API with Backbone and define a model for our App resource. We call this a UserApp in the code:

1 2 3
var UserApp = Backbone.Model.extend({
urlRoot: '/api/v1/user/app'
});
view raw models.js This Gist brought to you by GitHub.

Note, we use the urlRoot field to specify a root in our API that Backbone will then append the id variable to, in order to reference an instance of the model on the server. This results in a URL like we showed above.

Backbone: Built for APIs

Backbone works great with these types of APIs. In fact, if you don’t have an API set up this way, Backbone will probably feel inelegant, a useless wrapper around simple AJAX calls. To get the most out of it, focus on building an API first.

Let’s jump right in. Here is an example of fetching the data of a specific app that we own, that is saved on the Codiqa servers:

1 2 3 4 5 6 7 8 9 10 11
var a = new UserApp();
a.id = id;
a.fetch({
success: function(r) {
var name = r.get('name');
console.log('Loaded app:', name);
},
error: function(r) {
console.log('Unable to load app');
}
});
view raw app.js This Gist brought to you by GitHub.

Now, let’s say we change the name of the app. Here is how we can update the name both locally and on the server:

1 2 3 4 5 6 7 8 9 10
var app = new UserApp();
app.id = id;
app.save({'name': name}, {
success: function() {
console.log('Changed name of app');
},
error: function() {
console.log('Unable to change name of app');
}
});
view raw app.js This Gist brought to you by GitHub.

This makes it extremely easy to modify instances of apps. Contrast this with standard jQuery ajax calls where you must manage resource instances and network operations separately.

Part of using Backbone.js is making sure you are processing the data correctly on the server. Backbone sends a json string as the raw post data when sending a PUT or POST. Also when retrieving data to return to the client, we simply serialize our object and return a JSON string with content-type application/json. Here is an example from our python code on processing it:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
def _v1_user_app(request, appid):
# check authentication
 
if request.method == "POST":
try:
app_parsed = json.loads(request.raw_post_data)
# app_parsed is now a dictionary or hash object
# ...
return HttpResponse() # OK!
except:
# ...
elif request.method == "GET":
app = get_app_from_id(request.user, appid) # get app from database
return json_response({
'name': app.name,
...
})
view raw api.py This Gist brought to you by GitHub.

Collections

Backbone makes it very easy to treat a group of resources as a collection. We use collections to grab all of the historical version data for an app. Here is a definition of UserAppVersions, a collection of UserAppVersion model instances:

1 2 3 4 5 6 7 8 9
var UserAppVersions = Backbone.Collection.extend({
model: UserAppVersion,
url: function() {
return '/api/v1/user/app/' + this.id + '/versions';
},
parse: function(response) {
return response.versions;
}
});
view raw app.js This Gist brought to you by GitHub.

We can load all UserAppVersion instances by fetching the collection from the server:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
var versions = new UserAppVersions();
versions.id = appId;
versions.fetch({
error: function() {
console.log('Unable to load user app versions');
},
success: function(versions) {
console.log('Versions', versions);
// iterate over them with the each function, or with a for loop over version.models
versions.each(function(version) {
});
}
});
view raw app.js This Gist brought to you by GitHub.

When we call fetch, Backbone constructs a GET request to a URL that looks like this:

/api/v1/user/app/13817/versions

Where 13817 is the id of this example app. The server then responds with a JSON structure that looks like this:

1 2 3 4 5 6 7
{
"versions":[
{
"created_at":""
}
]
}
view raw versions.json This Gist brought to you by GitHub.

Where “versions” is an array of JSON objects that can be processed and loaded as UserAppVersion instances. We used the parse function of the Collection object to specify which part of the JSON response object represents the array of objects.

Benefits

I’ve found learning Backbone.js to have some pretty big benefits. Writing code that deals with networked resource “objects” is much easier and faster with Backbone. I’m now able to bang out little networked features here and there that used to be annoying to implement. Right now we are using a mixture of plain $.ajax calls and Backbone, but that’s mainly because I knew less Backbone when I first wrote our dashboard.

I also feel that Backbone has made me utilize an “api first” approach: developing an API for our networked resources, even if it’s a private one for now. That could make releasing a public API much easier in the future, and gives your application structure.

Up Next

In the next post in this series, I will run through how the actual workhorse of Codiqa uses Backbone: our drag-and-drop interface builder. This one is different because it’s all client side and utilizes views and inheritance, so you’ll want to come back for it!

I’d love to learn more about Backbone. Did I mess anything up? Could I do anything better?

Max

Hi, I'm Max, Co-founder of Codiqa, the easiest way to build jQuery Mobile prototypes. I'd love to talk with you: follow me!

More Posts

0 Flares Buffer 0 Buffer Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 0 Flares ×
Share →
Buffer
0 Flares Buffer 0 Buffer Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 0 Flares ×