DavidSpot Blog

Developer, super curious, a dog lover, sports fan and techie guy

From ASP.NET MVC to NodeJS (Sails.js & Total.js)

As a web developer I'm always seeking for new techie stuff. On the daily basis a work with .NET technologies but I like to explore another worlds and since nodejs is becoming so popular I decided to try something new and that's where a dropped on TotalJs and Sails.js framework.

Some TotalJS features (from their site):

RESTful routing

The framework supports a great routing mechanism. You can define a classic route, file route and websocket route. Each route can contains custom flags (e.g. xhr, post, get, json, put, delete, authorize, etc.). Routes can be defined as inline.

exports.install = function() {
    framework.route('/', view_homepage);
    framework.route('/api/log/', api_log, ['#middleware', 'put']);
    framework.route('/api/contact/', api_contact, ['json', 'post']);

function api_contact() {
    this.mail(CONFIG('mail.support'), 'mail-views/contact', this.body);
    this.json({ success: true });

function view_homepage() {
// ...


You can extend your web application with modules. The module can create routes, files and it influences the framework behaviours. The framework can uninstall module or install the module from URL address.

exports.id = 'module-name';
exports.version = '1.01';

exports.install = function() {
    framework.route('/api/module/{id}/', api_module);

function api_module(id) {
    this.json({ success: MODULE('module-name').sum(id, 2) === 5 });

exports.sum = function(a, b) {
// ...

Websocket example

The framework supports the WebSocket protocol, you can create realtime applications.

exports.install = function() {
    framework.websocket('/chat/', socket_chat, ['json']);

function socket_chat() {
    var self = this;

    self.on('open', function(client) {
        console.log('Online:', self.online);

    self.on('message', function(client, message) {

    self.on('close', function(client) {
        console.log('Online:', self.online);

Server-sents events example

Your application can communicate through Sever-Sent events (one way).

exports.install = function() {
    framework.websocket('/communication/', sse_communication, ['sse']);

function sse_communication() {
    var self = this;
    var counter = 0;
    var interval = setInterval(function() {

        // Creates a response for client in JSON format
        self.sse({ counter: counter++ });
        if (counter !== 50)


    }, 1000);

View engine

The framework supports built-in view engine. The engine supports conditions, loops and nested views. It compresses inline HTML, JavaScripts and CSS automatically. All views are rendered into the layout view. You can rewrite it.

@{title('This is title')}

@{helper address(street, city)}
    <div>@{street}, @{city}</div>

@{view('contact')} @{address('Bratislava', 'Slovakia')}

@{foreach m in model}


The localization is used by the view compilation. All localized text are stored in the resource files and $ total -translate (total binary) creates the resource file automatically from all views. The localization is a big part of views and it's very effective.

@{meta('This is title', '@(Description)', 'Keywords')}

<h1>@(Welcome in our page)</h1>

<p>@(Lorem ipsum dolor sit amet, consectetur adipisicing elit.
Doloribus nemo, obcaecati, accusamus excepturi porro id!Iure suscipit
sunt laborum ut animi est nesciunt molestiae pariatur
perspiciatis qui, ratione voluptatem ducimus.)</p>

@{if url !== '/'}
<a href="/">@(Homepage)</a>

Merging, mapping and image resizing

The framework supports realtime merging files (JavaScripts and styles), custom mapping and the image resizing through ImageMagick or GraphicsMagick.

// http://...../js/merge.js
framework.merge('/js/merge.js', '/js/a.js', '/js/b.js', '/js/c.js');

// http://...../js/jq.js
framework.mapping('/js/jq.js', 'http://code.jquery.com/jquery.min.js');

// http://...../img/small/logo.jpg
framework.resize('/img/small/*.jpg', 100, 100, {}, '/img/');
framework.resize('/img/blur/*.jpg', 100, 100, { blur: true }, '/img/');

Redirects and restrictions

Set your redirects and restrictions, it's simple. The redirect function supports permanent redirects and you can set the restriction to the IP address or headers.

framework.redirect('', 'http://localhost:8000');


// Allow only Chrome
// framework.restrictions.allow('user-agent', /Chrome/g);

// Disallow only Chrome
framework.restrictions.disallow('user-agent', /Chrome/g);

Array prototypes

The framework contains extended prototype of the array. This prototype contains many useful functions. Example:

var user = arrayUsers.find(function(doc, index) {
    return doc.alias === 'Peter';

arrayUsers.remove('alias', 'Lucia');

var first = arrayUsers.first();
var last = arrayUsers.last();
var order = arrayUsers.orderBy('alias');
var skip = order.skip(10);
var take = skip.take(10);

var fn = [];

fn.push(function(next) { next(); });
fn.push(function(next) { next(); });

fn.async(function() {

Other prototypes

The framework contains Strings, Numbers and Dates prototypes which are very helpful for creating web application. Example:

var date = new Date();
date = date.add('day', 5).add('minute', 20).add('h', -1);

console.log(date.format('dd.MM.yyyy HH:mm:ss')); // Custom format
console.log(date.format()); // ISO format without timezone

var same = date.compare(new Date()) === 0; // Date comparison
var number = 10030.34;

console.log(number.format(4, ',')) // Result: 10,030.3400
console.log(number.format(6, '.', ',')) // Result: 10.030,340000
console.log(number.format(0)) // Result: 10 030
number = 2;
console.log(number.padLeft(5)); // Result: 00002

var string = 'Value';
console.log('Hash: {0}.'.format(string.hash('sha1')));
number = '3483'.parseInt();

Extend the framework

The framework is extendible, you can install module or package from the URL address.

// Install the module from the URL address
INSTALL('module', 'https://modules.totaljs.com/session/v1.01/session.js');

// Or from your URL address
INSTALL('module', 'http://www.my-own-server.com/ddos.js');

// Install the package from the URL address
INSTALL('package', 'https://modules.totaljs.com/webcounter/v1.01/webcounter.package');

Run the framework without installation

Run the framework without NPM and without installation.

// The main function
function main() {
    framework.route('/', function() {


Some SailsJS features:

  • 100% JavaScript.

    Like other MVC frameworks, Sails is built with an emphasis on developer happiness and a convention-over-configuration philosophy. But Node.js takes this principle to the next level. Building on top of Sails means your app is written entirely in JavaScript, the language you and your team are already using in the browser. Since you spend less time context-shifting, you're able to write code in a more consistent style, which makes development more productive and fun.

  • Any database.

    Sails bundles a powerful ORM, Waterline, which provides a simple data access layer that just works, no matter what database you're using. In addition to a plethora of community projects, officially supported adapters exist for MySQL, MongoDB, PostgreSQL, Redis, and local disk.

  • Powerful associations.

    Sails offers a new take on the familiar relational model, aimed at making data modeling more practical. You can do all the same things you might be used to (one-to-many, many-to-many), but you can also assign multiple named associations per-model (for instance, a cake might have two collections of people: "havers" and "eaters"). Better yet, you can assign different models to different databases, and your associations/joins willstill work-- even across NoSQL and relational boundries. Sails has no problem implicitly/automatically joining a MySQL table with a Mongo collection and vice versa.

  • Auto-generate REST APIs.

    Sails comes with blueprints that help jumpstart your app's backend without writing any code. Just run sails generate api dentist and you'll get an API that lets you search, paginate, sort, filter, create, destroy, update, and associate dentists. Since theseblueprint actions are built on the same underlying technology as Sails, they also work with Websockets and any supported database out of the box.

  • Support WebSockets with no additional code.

    In the past, adding realtime/"comet" features meant maintaining two separate code bases. But since the request interpreter in Sails translates incoming socket messages for you, they're automatically compatible with every route in your Sails app, as well as any any existing Express routes/middleware. Normalization of parameters, the session, and the streaming interface are all taken care of. In other words, the code you write works with WebSockets and HTTP, without doing any extra work.

  • Declarative, reusable security policies.

    Sails provides basic security and role-based access control by default in the form of policies - simple, reusable middleware functions that run before your controllers and actions. Writing policies encourages encapsulation, which dramatically simplifies your business logic and reduces the total amount of code you need to write. Policies are interchangeable with Express/Connect middleware, which means you can plug in popular npm modules like Passport. Finally, like most things in Sails, your policies work for both WebSockets and HTTP automatically.

  • Front-end agnostic.

    While the promise of "one language/framework to rule them all" is certainly enticing, itisn't always realistic. Sails is compatible with any front-end strategy; whether it's Angular, Backbone, iOS/ObjC, Android/Java, Windows Phone, or something else that hasn't been invented yet. Plus it's easy to serve up the same API to be consumed by another web service or community of developers.

  • Flexible asset pipeline.

    If you are building an app for the browser, you're in luck. Sails ships with Grunt- which means your entire front-end asset workflow is completely customizable, and comes with support for all of the great Grunt modules which are already out there. That includes support for LESS, SASS, Stylus, CoffeeScript, JST, Jade, Handlebars, Dust, and many more. When you're ready to go into production, your assets are minified and gzipped automatically. You can even compile your static assets and push them out to a CDN like CloudFront to make your app load even faster. 

    Prefer Gulp? Check out the community generator by @PaulAvery.

  • Rock-solid foundation.

    Sails is built on Node.js, a popular, lightweight server-side technology that allows developers to write blazing fast, scalable network appliations in JavaScript. Sails usesExpress for handling HTTP requests, and wraps socket.io for managing WebSockets. So if your app ever needs to get really low-level, you can access the raw Express or socket.io objects. Another nice side-effect is that your existing Express routes work perfectly well in a Sails app, so migrating an existing Node app is a breeze.

For me, as asp.net mvc develper, both are great frameworks in terms of learning because it's so similar to asp.net mvc conventions that I fill that I already know how to work with it. 

The only problem I is the lack of documentation in the TotalJS which made the learning process harder.

The SailsJS on the other hand because of it's great documentation and youtube videos I found a easier solution for me to try a new framework and I must say i'm impressed with it, and even more know that I can use Typescript with it, the sintatic type tooling together with Visual Studio makes a nice environment to work. 

kudos to SailsJS team, great work :)