How to migrate from Node.ACS to Sails.js

Since April 2015, Appcelerator has launched Titanium SDK 4.0 and, with it, some major changes have been done.

We must jump from ACS (Appcelerator Cloud Services) to the new Arrow services (Arrow Cloud, Arrow DB and Arrow Push).

For the indies, the major “bad” change is that we have no more a free “NodeJS” platform where we can publish our web projects. We had NodeACS (a good MVC framework from Appcelerator to improve NodeJS apps), but now we cannot access to the new Arrow Cloud service (the substitute) if we don’t jump to the next plan (the Team plan, very expensive for just experiment with a project). The problem comes when you know that ACS will close the service on September 1, 2015 and you have no options to migrate your Node project inside the Appcelerator platform for free.

This is the current situation in July 2015 (could change in future). I had two projects to migrate and, obviously, I needed a solution. So I searched for a (initial) free and scalable hosting (I found that Openshift from RedHat was a great option) and also I needed to change my MVC framework.

After two days viewing alternatives, I decided to choose Sails.js because its growth, community and well-structured project. But I needed to modify some code to jump from NodeACS to Sails.js and, if you are in the same way, maybe this simple (but time-consuming for me while experiencing) guide can help you. Let’s begin.

NOTES: This is not a guide to “install Sails”, so I’m assuming that you have it installed. Also, Sails uses by default EJS templates (can use others) so you will have no problems with your current NodeACS views (will work exactly the same).

Create the Sails structure first

$ sails new <project_name>

Changes in the NodeACS app.js file

In NodeACS we need to config the app start in the acs/app.js file, but it’s not recommended to modify the original app.js from Sails. Instead, you have the file config/bootstrap.js to initialize and share all that you need (there are more ways to achieve this, but for our purpose this will work fine).

What we need is to move the ACS.init(APP_KEY) to the new Arrow commands and make it available globally.

So first of all, move the acs/app.js custom logic to config/bootstrap.js, i.e.

From (acs/app.js):
var ACS = require(‘acs-node’);
var APP_KEY = ‘myKey’;
// Initialize ACS credentials
ACS.init(APP_KEY);
To (config/bootstrap.js):
module.exports.bootstrap = function(next) {
var APP_KEY = ‘myKey’;
var ArrowDB = require(‘arrowdb’);
// Save it in global object sails
sails.arrowDBApp = new ArrowDB(APP_KEY);
next();
};

In this way, we have arrowDBApp available in sails object and we can call any API from anywhere. For example, if you need to call user update in api/controllers/UserController.js you only need to do:

sails.arrowDBApp.usersUpdate(params, function(err, result) {
if (err) {
// your code
} else {
// your code
}
});

API calls

This is not related to Sails, but because we change from the old ACS package to the new arrowdb, the API calls have changed. The changes are basically three: the API name, the resulting function and the result value itself.

From:
ACS.Users.create(params, function(data) {
if (data.success) {
// Your code
} else {
console.log('Error');
}
});
To:
sails.arrowDBApp.usersCreate(params, function(err, result) {
if (err) {
console.log('Error');
} else {
// Your data is now in result.body.response instead of the old data var
}
});

Node modules

Copy it to the same node_modules folder on sails. Avoid to copy i18n (it’s built-in). MomentJS is not built-in, so install it if you need:
$ npm install moment --save

Static files

Copy the public folder to the assets folder, as is.

Routes

You need to configure the new routes in config/routes.js, getting the old routes from the acs/config.json file and put in the Sails format.

From (acs/config.json):
{
"routes":
[
{"path": "/", "callback": "application#index"},
{"path": "/login", "method":"post", "callback": "application#login"}
]
}
To (config/routes.js):
module.exports.routes = {
'/': 'ApplicationController.index',
'post /login': 'ApplicationController.login'
}

Controllers

You need to change all your old controllers to meet the convention of <Name>Controller.js. Then you must alter the ACS MVC structure to the new Sails structure for Controllers

From: 
function index(req, res) {
res.render(‘index’, { page: ‘Home’ });
}
To:
module.exports = {
index: function (req, res) {
res.render(‘index’, { page: ‘Home’ });
}
};

Filters (now Policies)

The filters change a little in Sails, but I think they are more powerful. Read the documentation of Sails about policies and set your filters on the /config/policies.js

Internationalization (if you used https://github.com/mashpie/i18n-node)

Config it on /config folder
Add your languages in /config/locales

And that’s all. Now try $ sails lift command and see if all is working!