Dom Christie

Backbone.js Patterns Pt.2: Don’t make me think

Different programming languages have different naming conventions. When working with Ruby, for example, it is advised that you separate multi-word variables with underscores. In JavaScript, camelCasing is generally the norm. So when dealing with data that is shared across different environments, you may find yourself having to remember what style to use, e.g. “Was it user.get('first_name'), or user.get('firstName')?”.

This is where humps is your friend.

humps is a small JavaScript library (~100 LoC) that simply converts underscored object keys (and strings) to camelCased, and vice versa (as well as other styles, like PascalCase). By using humps in the toJSON and parse methods, we can seamlessly work with the conventions of each language.

toJSON and parse are methods that are typically used to customise the data being sent to and from the server. toJSON should be used to prepare a model’s attributes for synchronisation [1]; whereas parse is typically called when data is sent from the server, and therefore can be used to prepare a model’s attributes before they are set on the model itself.

Starting with the parse method, overwrite Backbone.Model.prototype.parse, passing the results of the old `parse` method into humps.camelizeKeys:

(function() {
  var oldParse = Backbone.Model.prototype.parse;
  Backbone.Model.prototype.parse = function() {
    var parsed = oldParse.apply(this, arguments);
    return humps.camelizeKeys(parsed);
  };
})();

So now, the following JSON:

{ "first_name": "Jon", "last_name": "Snow", "is_steward": true }

will be converted to camelCase and will be accessible on the model as follows:

// assuming user is an instance of a Backbone model
user.get('firstName'); // "Jon"
user.get('lastName'); // "Snow"
user.get('isSteward'); // true

Remember, that parse is only called when a model’s is updated via a fetch or save. If you are populating a model’s attributes manually, you’ll need to pass in { parse: true }:

var user = new User({
  "first_name": "Jon"
}, { parse: true });

It’ll also work with nested objects.

The same pattern can be applied to toJSON, which will convert camelCased object keys (back) to underscored:

(function() {
  var oldToJSON = Backbone.Model.prototype.toJSON;
  Backbone.Model.prototype.toJSON = function() {
    var json = oldToJSON.apply(this, arguments);
    return humps.decamelizeKeys(json);
  };
})();

Feedback welcome via Twitter, or email.

Part 3 in this miniseries will extend the toJSON method to exclude non-persisted attributes from its output.

[1] The Backbone.js documentation for toJSON previously suggested that it could be used to clone a model’s attributes for use in a template, as well as for persistence. Following a discussion on the purpose of toJSON, it was decided that this “double duty” should be simplified. It is now not recommended for preparing a model for rendering.