UPDATE: Since io.js has been merged with the Node.js project this post has been updated for accuracy and comprehensiveness. There won’t be any further io.js releases. All of the features in io.js are available in Node.js v4 and above.
Why sails.js
A large number of projects on Node.js platform are carried out in the manner of the manner of separating and isolating the backend from the frontend. Namely RESTful backend API is usually implemented using express.js, loopback, hapi, restify, etc. and frontend application is implemented using angular.js, react.js + flux, backbone.js, etc.
But often enough there are cases when the customer (or sometimes even the developer’s team) wants to implement a classical MVC application with Node.js platform.
Recently our team have had to deal with such a project. And in this situation the best choice for achieving the goals, is to use sails.js framework. This framework provides an elegant, comfortable and easy way to build MVC application.
The slogan of this framework is: “Built for developers by developers”
Here’s what it says on the official website of the framework:
Sails makes it easy to build custom, enterprise-grade Node.js apps. It is designed to emulate the familiar MVC pattern of frameworks like Ruby on Rails, but with support for the requirements of modern apps: data-driven APIs with a scalable, service-oriented architecture. It’s especially good for building chat, realtime dashboards, or multiplayer games; but you can use it for any web application project – top to bottom. http://sailsjs.org
In this article I would like to share our experience in the development using this framework. My impressions are quite ambiguous. On the one hand, the framework has almost all the tools required to develop a full-stack web application.
On the other hand, a lot of frameworks components are still raw. This framework runs on top of express.js (so far it uses 3.x version). So, in theory, all you do in express can be done in sails.
The skeleton project has a fairly strict structure where the main components are divided into separate folders, for example:
- api/controllers
- api/models
- api/services
- views
- configs
Nevertheless, some things in the basic project structure were missing for me. That’s why I extended it by adding the components like:
- api/bootstrapers
- api/middlewares
These are the folders containing custom application bootstrapers (initializers) and express request middlewares respectively.
Sails.js comes with a powerful CLI tool which allows to generate controllers, models, services, run and debug application etc. The CLI tool capabilities may be extended using sails generators API.
You can create both RESTful and action controllers. Besides, sails.js provides a transparent way to work with web-sockets, namely, it works in conjunction with socket.io and all web-sockets’ requests are transmitted to the server controllers calls.
As for the view rendering engine, the choice is wide enough: EJS, Jade,Handlerbars.js, etc. (http://sailsjs.org/documentation/concepts/views/view-engines)
Personally I prefer and recommend you to use JADE.
There is also a task runner called Grunt.js integrated in the skeleton sails.js application. A lot of essential tasks are already embedded in the project: compilation of LESS (or Sass) sources, minification and concatenation of JavaScript files, JST templates compilation, etc. If any task is missing, you can easily add it by yourself.
Also, the project comes with a wonderful complimentary task called sails-linker, which links your view files to the frontend assets.
For more information about this task check the link https://www.npmjs.com/package/grunt-sails-linker.
The access control functionality is implemented with sails.js policies. In fact, this is an ACL that is applied only to the controllers and their actions. Its idea is easily understood and used, but it is sometimes not really flexible when it comes to a large application (for example, you cannot restrict access to all controllers located in the directory controllers/admin/*). Although in most cases the policies’ capabilities are enough to satisfy application requirements.Actually, the number of great features and capabilities of sails.js is very large to list them all in one article.
More details about all the features of the framework are given here: Sails Concepts
A fly in the ointment and workarounds
Still, I would like to mention a few things which I did not like.
To interact with the database, sails.js uses ORM called Waterline. This is one of the weaknesses of the framework. This ORM is aimed at the unification of working with SQL and NoSQL databases. The API to fetch the data is quite limited and most of the SQL queries have to be written in a raw format, for example, while using waterline query builder, you will not be able to join multiple tables and filter the results by “joined” fields. The same problems apply to NoSQL samples, for instance, you will not be able to use all the charm of the aggregate API of the MongoDB.
A better choice is to use Sequelize.js ORM for the relational databases and mongoose ODM for the MongoDB.
Built-in user authentication functionality is missing as well. For the authentication logic implementation I recommend using passport.js. There is a great article on passport.js and sails.js cooperation.
The routing system is sometimes not convenient to use. All routes paths must be declared explicitly, that is, you can’t just say that CustomerController is a RESTful representation of the /application/customer/ path.
Also the URL part’s auto-resolving is absent, for example, you cannot do something like /customer/:action -> CustomerController.{action}
.
Besides, there is no opportunity to assemble the route URL address by the controller and action names.
It lacks integration with the frontend package manager bower. It isn’t a problem to do it yourself, but it would be better to make this feature come out of the box.
Lack of Node.js’ own processes manager (like it is done for the loopback framework). Here we come to the aid of a remarkable utility called PM2.
Conclusion
In my view, the sails.js framework is quite flexible and even if it’s missing any feature, you can add it by yourself, like using sails.js hooks API , or you can find and use a third-party npm package. For example, during development I needed a concept of view helpers and I easily added it with just a single middleware, where I exposed all necessary helper functions to the views using express.js res.locals.
The framework is constantly evolving and it has already gathered more than 11 000 stars on GitHub!