I Eat Libraries Like Kobayashi Eats Hot Dogs

That‘s right. I pick out a node library to use for a project and try it and dump it for something else in a matter of days. There’s nothing wrong with that for me, working alone, at the very beginning of a very iterative approach to a novel solution. But if you aren‘t me, and I assure you, you’re not, don‘t worry I’ll still try to make this useful and helpful if you're trying to decide what library you want your node project to use.

Some Backstory, Bro

First off, please see this stackoverflow answer. When I first saw this, I said to myself, “self, you are smarter than that ponce, use a framework library.” Boy am I eating my words now. I started out with GeddyJs and that ended soon there after because there was no way to debug it.

Then I got the hang of some closer-to-node work by using Express. That turned out to be a great experience. Express has great documentation and its light-weightiness helped me get into some actual node stuff that I was too lazy to try out before. It kind of puffed up my node ego, so when I started a new project that has a service (kind of a scheduled task??? still working out the details) layer as well as an api layer (you know, easy routes returning data), I thought, "I can leave this framework crap behind and head for a more node-y solution by using the flatiron tools."

Famous Last Effing Words

Flatiron has one thing going for it - it is very modular and extensible. Flatiron also has one thing going against it - it is very new. There aren‘t any consistent API docs - each module has a pretty in depth README.md, but nothing super formal, or very helpful. Each module’s github repo has some samples and examples and some wiki pages, but again, nothing super helpful. So I started out working on resourceful to create some models and I hit my first and last bump.

Resourceful is kind of this model-meets-data-layer-omni-adapter. On the one hand it gives you a uniform way to create and maintain data models in your app. And on the other it uses ‘Engines’ to connect with your datasource, so you don't have to worry about it. It seems like awesome sauce, and for sure, one day it will be awesome sauce. But not today. They only package two Engines - in memory, and couchdb. I need to be able to use a database and other restful services like twitter for example. There's a lot of stuff out there, but nothing I was particularly brave enough to try, so I just gave up on the restful thing and used request to get the api queries and other stuff out of the way.

But I still needed to store my own process data after pulling in from these various restful services. So I signed up for a couchdb account and tried out their couchdb engine. It was a terrible failure. The couchdb engine uses cradle as the couchdb adapter and I think I saw a reference to request as well. The problem is that in all the adapting from resourceful to engine to cradle, my url/uri got absolutely butchered. Late one night I cried myself to sleep as decided I would have to abandon flatiron if I ever wanted to get any of this work done.

The Light at the End of the Tunnel

The project I‘m referring to started out as an awkward, but functional and cool little client app. But it does things that no client app should do and its data isn’t persistent. It uses Backbone.js which as of late has become my favorite client side kick ass tool.

While backbone was designed to play nice with node, it is tied inextricably to jQuery. I‘m not really sure how helpful that is on a server, but I’ll just let it slide. One of the things I really love about Backbone is that it‘s the only really good emulation of Class like inheritence in client side javascript that I’ve been able to find. So I'm now Stonewall Jackson at the First Manassas, doggedly determined to take out the Backbone.ajax parts and put in my new, more better node thingamajigs.

How to Override Backbone.sync To Use Any Node Data Module

This is where the article might actually become useful. Backbone.ajax is backbone's single point of entry for ajax requests. Backbone.sync is backbone's single point of entry for any CRUD transactions used by its Models or Collections. It then uses $.ajax which is the real problem. The solution is pretty straight forward - create a subclass of Model and Collection that override sync and implement either a database adapter or, in my case, just use request and adapt some of the options and callbacks. Here's my currently functional code for what I now call RequestModel:

RequestModel.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
var Request = require('request');
var Backbone = require('backbone');
var _ = require('underscore')._;

var RequestModel = Backbone.Model.extend({
  sync: function sync(method, model, options) {
    var type = methodMap[method];

    // Default options, unless specified.
    options || (options = {});

    // Default JSON-request options.
    var params = {method: type, json: true};

    // Ensure that we have a URL.
    if (!options.url) {
      params.url = _.result(model, 'url') || urlError();
    }

    // Ensure that we have the appropriate request data.
    if (!options.data && model && (method === 'create' || method === 'update')) {
      params.contentType = 'application/json';
      params.body = JSON.stringify(model);
    }

    // adapt jquery success and error callbacks to the model and use in onRequire callback
    if (options.success) model._successCallback = options.success;
    if (options.error) model._errorCallback = options.error;

    // store options
    model._requestOptionsStore = options;

    // Make the request, allowing the user to override any Ajax options.
    var reqOpts = _.extend(params, options);
    return Request(reqOpts, _.bind(this.onRequest, model));
  },

  onRequest: function onRequire(error, response, body) {
    if ((typeof error === 'undefined' || error === null) &&
        typeof body === 'object') {
      this.onSuccess(body, error, response);
    } else {
      this.onError(body, error, response);
    }
  },

  onError: function onError(response, status, xhr) {
    if (this._errorCallback) this._errorCallback(response, status, xhr);
    this.trigger('error', this, xhr, this._requestOptionsStore);
  },

  onSuccess: function onSuccess(response, status, xhr) {
    if (this._successCallback) this._successCallback(response, status, xhr);
    this.trigger('sync', this, response, this._requestOptionsStore);
  }
});

module.exports = RequestModel;

Now this isn't as Omni Awesome as Resourceful, because you can't change data layers (or Engines) at runtime. But I could create a similar sync for models that uses mongoose or cradle. They would each require a new Backbone.sync override and each model or collection I create can only extend one data layer. I haven't built them yet, but I suspect I will also need to adapt the schema thing. Moving along, using the override looks something like this:

ConcreteRequestModel.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  var RequestModel = require('../abstract/RequestModel');

  var ConcreteRequestModel = RequestModel.extend({
    initialize: function initialize(attributes) {
      // do some constructor stuff
      this.fetch();
    },

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

  module.exports = ConcreteRequestModel;

Postscript

I used this awesome post to get this blog running from Cloud9. Thanks!