TodosMVC with Backbone.js, Node.js and MongoDB

This demo was written to illustrate how a server-side JavaScript solution could be applied to the TodosMVC application. I used Underscore.js, Backbone.js, Node.js, Express, Jade, Stylus, Mongoose and MongoDB.

Fork this project on Github

A newer version using Socket.io and Redis for multi-user editing and record locking can be forked here on Github.

Technologies Used In This Demo

  • Underscore.js – A utility-belt library for JavaScript without extending any of the built-in JavaScript objects.
  • Backbone.js – Gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.
  • jQuery – A fast, concise, library that simplifies how to traverse HTML documents, handle events, perform animations, and add AJAX.
  • Node.js – Event-driven I/O server-side JavaScript environment based on V8.
  • Express – High performance, high class web development for node.js.
  • Jade – High performance template engine heavily influenced by Haml and implemented with JavaScript for node.js.
  • Stylus – Expressive, dynamic, robust CSS for node.js
  • Mongoose – A MongoDB object modeling tool designed to work in an asynchronous environment.
  • MongoDB – A scalable, high-performance, open source NoSQL database.

Running the Demo

  1. Install node.js.
  2. Install MongoDB.
  3. Start the MongoDB server from a terminal window:
    $ mongod
  4. Change the working directory to the project root:
    $ cd <path to todosmvc>/labs/architecture-examples/backbone_node_mongo/
  5. Install dependencies using the node package manger (npm).
    $ sudo npm link
  6. Start the Todos demo server from a different terminal window:
    $ node app
  7. Visit http://localhost:3000 in a web browser.

Interesting Parts

Here are a few interesting parts of the project that I wanted to highlight.

Create the Model Schema

Working with Mongoose is awesome. Simply define a schema that Mongoose will use to proxy the database. I know MongoDB is a schemaless document store but the schema is for Mongoose to use.

var mongoose = require('mongoose'),

  TodoSchema = new mongoose.Schema({
    title: { 'type': String, 'default': 'empty todo...' },
    order: { 'type': Number },
    done: { 'type': Boolean, 'default': false }
  });

module.exports = mongoose.model('Todo', TodoSchema);

Setting Up the Routers

In order for Express to handle requests from the Backbone application routers must be set up to route RESTful URIs to handlers. Backbone has a default URI schema so the Express router is created to match it. The schema is as follow:

POST /todo //CREATE
GET /todo/:id //READ
PUT /todo/:id //UPDATE
DELETE /todo/:id //DELETE

For example the READ handler looks like this in my utils/crudUtils.js file.

(function (exports) {

  "use strict";

  // List, Create, Update and Delete omitted for brevity
  // See full source on Github.

  //------------------------------
  // Read
  //
  // Generate and return a handler with an injected model
  function getReadController(model) {
    // Returning a closure so that the model can be stored
    // in this function's environment
    return function (req, res) {
      // Look in MongoDB for the record
      model.findById(req.params.id, function (err, result) {
        if (err) {
          res.send(409, err);
        } else {
          res.send(result);
        }
      });
    };
  }

  // Export function so it's accessible outside of this module
  exports.initRoutesForModel = function (options) {
    var app = options.app
      , model = options.model
      , path
      , pathWithId;

    // We can only set up routers if we have a reference to the
    // Express app we want to create them on and the model
    // we want to create them for
    if (!app || !model) {
      return;
    }

    // Generate the RESTful URIs we expect to see from Backbone
    path = options.path || '/' + model.modelName.toLowerCase();
    pathWithId = path + '/:id';

    app.get(path, getListController(model));         // List all Todos
    app.post(path, getCreateController(model));      // CREATE
    app.get(pathWithId, getReadController(model));   // READ
    app.put(pathWithId, getUpdateController(model)); // UPDATE
    app.del(pathWithId, getDeleteController(model)); // DELETE
  };

}(exports));

Credit

5 Responses to TodosMVC with Backbone.js, Node.js and MongoDB
  1. Felipe Sabino Reply

    is there a special reason for you to point to a commit instead of the master ?https://github.com/jamesor/todomvc/tree/master/labs/architecture-examples/backbone_node_mongo

    • jamesor Reply

       I am pointing to the master.  I was just pointing to a particular folder
      inside master because I wanted to make it easier for people to find the
      project I was referring to in the blog post.  The repository is a
      collection of many examples and I was afraid people would find what
      folder it was in.

  2. jamesor Reply

    I am pointing to the master.  I was just pointing to a particular folder inside master because I wanted to make it easier for people to find the project I was referring to in the blog post.  The repository is a collection of many examples and I was afraid people would find what folder it was in.

  3. Kcotzen Reply

    Very good post! Thanks a lot.
    I have a doubt, you said:
     ” I know MongoDB is a schemaless document store but the schema is for Mongoose to use.”

    According to this, What happen if I want to get a list from a collection and every document has a different schema?.

    In that case Mongoose wont work? is it Just for documents with a schema defined?

  4. Jean-Pierre Gygax Reply

    Just what the doctor ordered – I’m looking at Backbone for the first time and was afraid its modelling system would clash with Mongoose’s. But, if it’s *that* simple to get going..!
    I fully intend to just steal your code :-)

Leave a Reply

Your email address will not be published. Please enter your name, email and a comment.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>