boldr by Nicolas Mérouze

MVC with Node.js - Which modules?

When you start a new technology you may be lost. Node.js is young (1 year today) but there's already a bunch of frameworks (express seems to be the most advanced) and a lot of modules. The best way to begin is to explore the ecosystem. To do that, let's create our own Model-View-Controller stack.

NOTE: The whole example is available on GitHub and not all the code is in the article, so be sure to check it out.

Models

There's a lot of modules for databases and some of them have ORMs. We can use Redis, MongoDB, CouchDB, Tokyo Cabinet, Postgres, Sqlite 3, Riak... For this example we're going to use node-dirty which do not require any database installation. node-dirty is a fast JSON store and it's easy to use, have a look at the following code:

/* Requirements */
require.paths.unshift("./vendor/node-dirty/lib");

var sys = require("sys"),
    Dirty = require("dirty").Dirty;

/* Model */
var posts = new Dirty("posts.dirty", { flushInterval: 10 });

/* Persistence */
var post  = { title: "Awesome post" };
posts.add(post);

/* Querying */
sys.puts(posts.get(post._id).title);

Views

Now we have data we will need views to display them. I've already written something about Mustache.js and for this example I'm gonna use it too but there are other modules available for templating. You can use EJS, HAML, Sass (for css only)...

To use Mustache.js, don't forget to use the one from the commonjs branch (master will not work with Node.js). There's another implementation faster and with built-in async named Mu.

Controllers

The important part here is not the controller itself because it's just a function which will be called by the router. There are some routers but the most interesting is Scylla mainly because it uses EJSGI (an async Rack-like interface for Javascript).

With Scylla we're defining the route with a string containing the HTTP verb and the pattern. Then we bind a function to it.

/* Requirements */
require.paths.unshift("./vendor/ejsgi/lib");
require.paths.unshift("./vendor/node-scylla/lib");

var scylla = require("scylla"),
    ejsgi = require("ejsgi");

/* Controller */
var HomeController = {
  index: function(req) {
    var body = "Hello World!";

    var res = {
      body: new req.jsgi.stream(),
      status: 200,
      headers: {
        "content-type": "text/html",
        "content-length": body.length
      }
    };
    res.body.write(body);
    res.body.close();

    return res;
  }
};

/* Router */
function Router() { scylla.Base.call(this); }
Router.prototype = Object.create(scylla.Base.prototype);
process.mixin(Router.prototype, { "GET /": HomeController.index });

/* Server */
ejsgi.Server(new Router().adapter("ejsgi"), "localhost", 8000).start();

NOTE: I included the router stuff in the controller part because most of the code is in the controller.

Conclusion

As we've seen there are a lot of modules for each part of the MVC stack. It's kinda difficult to choose but it's mainly about what you like (which database you want to use, which templating engine you like and which is the most powerful router).

Most frameworks for Node.js are not fully agnostic (nor fully opiniated) yet so it can be a dealbreaker if you like things that ain't in a framework you want to use. If you're like this you can comment the article and write about your preferences. It will maybe ease the choice for newcomers in the Node.s world.

If you liked the article and/or want to talk to me about it, you can follow me on twitter.