Sails.js and Express.js, the Dynamic Duo

Awhile back, I decided to finally give Node.js a try in a real-world application. A friend has been coding in it for some time and I liked Node.js’s concept and even played with it a bit, but never really committed.

Then an opportunity in an overhaul of a production site came up and I thought if Walmart and LinkedIn are willing to use it, why not me?

The first thing I had to do was to pick a framework. There was no way I was coding a real application from

require('http').createServer()

Google “node.js framework” and an overwhelming choices appear. Sails.js, a framework based on Express.js, is my choice. How I picked it is a story for another day. This post is about using Sails.js with Express.js

Version: This post is relevant for Sails.js 0.9.x

Getting started in Sails.js

Sails.js is really strong in letting you start coding your business logic right away using the MVC pattern (or MV*, replace * with your pattern of preference). Express.js’s chain of middleware lets you process requests in any way you like.

To emphasize just how easy it is to start writing business logic with Sails.js, here are 5 steps from start to finish on how to do it:
1. Install Sails.js globally so we can access it from the command line:

npm install sails -g

2. Generate Sails.js app skeleton:

sails new small

to generate the skeleton for an application called smallapp

3. Install Sails.js locally in smallapp. This is not mandatory since Sails.js is already installed globally and accessible there. Installing Sails.js locally has benefits, particularly in ease of deployment so I usually prefer to do it:

cd smallapp
npm install sails --save

4. Create a controller in api/controllers and write business logic there.

5. Place your website routes along with their corresponding controller actions in config/routes.js. The default routes.js has a lot of instructional comments and sample routes in it. Delete them if you wish.

Barebone example of the above is available at Github

Adding middleware to Sails.js’s Express

Sails.js allows access to the underlying Express.js which it is based on. In Sails.js 0.9.x, it’s sails.express.app

Whereas Sails.js allows you to organize your code in the MVC pattern with minimal ceremony (ie boiler-plate code) and therefore perfect for separating UI from presentation logic from business logic, Express.js middleware is perfect for functions that cut across the application layers and that needs to be applied to all requests and responses. Functions such as logging, authentication & authorization, and internationalization. Middleware for Sails.js are place in config/express.js like so:

module.exports.express = {
  customMiddleware: function (app) {
    app.use(function mymiddleware1(req, res, next) {
      ...
    });
    app.use(function mymiddleware2(req, res, next) {
      ...
    });
  }
};
Name the middleware: using named functions for middleware makes it easier to identify them in the middleware chain, stack[], during debugging
Position matters: Sails.js inserts custom middleware after cookieParser, session, bodyParser, and before the Express router. For more detail, see Sails.js source code in lib/express/index.js
Sails.js 0.10 provides an entirely different way to add Express middleware. However, there is backward-compatibility to 0.9.x so the express.customMiddleware method would still work in 0.10.

An useful middleware to log all requests processed by Sails.js

Logging detail of a request that gets received by Sails.js is a very common use case. Normally, interesting info like request URL, headers, response time, etc.
The easiest way to do this is with an Express middleware in config/express.js:

var bunyan = require('bunyan');
var log = bunyan.createLogger(
  {
    name: 'applog',
    streams: [
      {
        level: 'info',
        stream: process.stdout            // log INFO and above to stdout
      }
    ]
  });

module.exports.express = {
  customMiddleware: function (app) {
    // request logger, too bad I can't put it any higher in 0.9.x....
    app.use(function requestLogger(req, res, next) {
      var start = new Date();
      res.on('finish', function () {
        var responseTime = ((new Date()).getTime() - start.getTime()) / 1000.0; // in seconds (to be in same unit of measure as nginx)
        req.responseTime = responseTime;
        log.info({ req: req }, 'requestlog');
      });
      next();

    });
  }
};

The example above uses Bunyan for logging. This is just a personal preference. You may, of course, use Sails.js’s builtin logging or your own favorite logging package.

Is there a more “Sails” way than using an Express middleware to log all requests? Let me know! 🙂