Application Integration

Migrating Node.ACS Applications to Arrow

On September 1, 2015, Appcelerator’s Node.ACS servers will be discontinued in favor of Arrow Cloud, which is part of the new 4.0 Platform. (NB: This retirement date was subsequently pushed by more than a year to October 3, 2016, to give users adequate time to migrate.)

If you have a Node.ACS application and the published URL is https://<SUBDOMAIN_TOKEN>.cloudapp.appcelerator.com, you’ll need to migrate to Arrow Cloud. This will generate a new URL you’ll also need to update in your client apps.

To migrate, you will first need to purchase Arrow Cloud capacity. Then simply follow the steps below. (These same steps are also detailed in the docs here).

Create an Arrow project

Before starting, first create an Arrow project by executing the command below in your workspace directory:

appc new -t arrow -n ArrowProject

package.json

If you have any special settings or dependencies in your Node.ACS project’s package.json file, add them to the same file in your new Arrow project. Do not overwrite any existing keys.

Express app instance

Node.ACS used Express 3.x, while Arrow Builder uses Express 4.x. For details about migrating to Express 4, see https://expressjs.com/guide/migrating-4.html.

Express version

To access the Express instance in an Arrow project, use the app property of the Arrow instance. For the API and Route components, an Arrow instance is passed to the request and response objects as the server property.

Example

var Arrow = require('arrow'),
    favicon = require('serve-favicon'),
    server = new Arrow();
server.app.use(favicon(__dirname + '/web/public/images/favicon.ico'));

socket.io instance

An Arrow application does not include socket.io by default. To include socket.io in an Arrow application:

  • In the package.json file, add socket.io as a dependency.
  • In the app.js, in the started event listener, load the socket.io module and pass it the server instance (Arrow instance’s server property), then make API calls to the socket.io instance. If you assign the socket.io instance to a property of the Arrow instance, you can access the socket.io instance with that property wherever an Arrow instance is passed to a method.
  • Any client-side code, such as the view templates, will need to include the socket.io.js client script. Note that when the client connects to the socket.io server (Arrow application), you will need to update the URL when switching between testing the project locally or when its published to Arrow Cloud.

Example

The following example creates a basic chat application.
Add socket.io as a dependency to the Arrow project.

//package.json
{
  ...
  dependencies: {
    ...
    'socket.io': '*'
  }
}

Loads the socket.io module and creates an instance.

//app.js
var Arrow = require('arrow'),
    server = new Arrow();
server.on('started', function () {
    // Creates a socket.io instance and attaches it to the Arrow instance
    this.io = require('socket.io')(this.server, {logger: this.logger});
    // Adds a connection listener 
    this.io.on('connection', function(socket) {
        console.log('a user connected ' + socket.id);
        // Listens for a new message
        socket.on('message', function(data) {
            // Alerts all clients there is a new message
            this.io.emit('message', data);
        });
    });
});
// start the server
server.start(); 

Then, add the socket.io client code to your views or other client-side code.

//web/views/chat.html
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13pxHelvetica, Arial; }
.inputMessage { padding: 3px; position: fixed; bottom: 0; width: 100%; }
.messages { list-style-type: none; margin: 0; padding: 0; }
.messagesli { padding: 5px10px; }
.messagesli:nth-child(odd) { background: #eee; }
</style>
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<!-- Include the socket.io client code -->
<scriptsrc="https://cdn.socket.io/socket.io-1.3.5.js"></script>
<script>
$(document).ready(function() {
// For a production application, you need to change the URL to the published URL
varsocket = io.connect('https://localhost:8080');
$('.inputMessage').keydown(function(event) {
if (event.keyCode == 13) {
socket.emit('message', socket.id + ':' + $('.inputMessage').val());
$('.inputMessage').val('');
returnfalse;
}
});
socket.on('message', function(msg){
$('.messages').append($('<li>').text(msg));
});
socket.on('connect', function(){
$('.messages').append($('</li><li>').text('You are ' + socket.id));
});
});
</script>
<div class="chatArea">
</div>
<input class="inputMessage" type="text" placeholder="Type here..." />

Note you need to implement an Arrow Route to render the HTML.

//web/route/chat.js
var Arrow = require('arrow');
var ChatRoute = Arrow.Router.extend({
    name: 'chat',
    path: '/chat',
    method: 'GET',
    description: 'Access the chat client',
    action: function (req, res) {
        res.render('chat');
    }
});
module.exports = ChatRoute; 

app.js

If you add any logic to the start() or stop() methods in the app.js file, you can add the same logic in the Arrow instance’s event listeners for the starting and stopping events, respectively.

Example

The Node.ACS project logs in and out of an ArrowDB account when the application starts and stops. The same method calls can be added to the event listeners in an Arrow application.

//NodeACSProject/app.js
var ArrowDB = require('arrowdb'),
    arrowDBApp = new ArrowDB('API_KEY');
 
function start() {
    var data = {
        login: 'user',
        password: 'user'
    };
    arrowDBApp.usersLogin(data, function(err, result) {
        // Logic
    });  
}
 
function stop() {
    arrowDBApp.usersLogout(function(err, result) {
        // Logic
    }); 
}
//ArrowProject/app.js
var Arrow = require('arrow'),
    server = new Arrow(),
    ArrowDB = require('arrowdb'),
    arrowDBApp = new ArrowDB('API_KEY');
server.on('starting', function () {
    var data = {
        login: 'user',
        password: 'user'
    };
    arrowDBApp.usersLogin(data, function(err, result) {
        // Logic
    });  
}
server.on('stopping', function () {
    arrowDBApp.usersLogout(function(err, result) {
        // Logic
    }); 
}
server.start();

config.json

routes
All routes are declared in the config.json file of your Node.ACS application may be declared as:

  • Arrow route located in the web/routes folder of the Arrow project if the route renders UI. For details, see the example below and Arrow Web.
  • Arrow Model if the route is a simple data object stored in the cloud that you want to have standardized HTTP endpoints. For details, see Arrow Models.
  • Arrow API if the route performs more complex operations and you want to have a custom HTTP endpoint. For details, see Arrow APIs.

Example

The config.json file defines a route that when someone accesses SERVER_ADDRESS/foobar, the Node.ACS application executes the bar() method in the controllers/foo.js file.

//config.json
{
  "routes":
  [
    {"path": "/foobar", "method": "get", "callback": "foo#bar"}
  ]
}

To use the same route in Arrow, create a CommonJS module, which loads the arrow module, then call the module’s Router.extend() method to declare the route. Pass a dictionary to the extend() method with the following keys defined (all keys are required):

KeyDescription
nameThe name of your route.
pathThe endpoint/path for your route.
methodHTTP verb (‘DELETE’, ‘GET’, ‘POST’ or ‘PUT’)
descriptionA description for your route. This is used for documentation purposes.
actionFunction that allows you to interact with Arrow APIs and Models and send data to your template engine.

Finally, expose the route using the modules.exports variable.

//web/routes/foobar.js
var Arrow = require('arrow');
var Foobar = Arrow.Router.extend({
    name: 'foobar',
    path: '/foobar',
    method: 'GET',
    description: 'Does foo',
    action: function (req, res) {
        res.render('example');
    }
});
module.exports = Foobar;

Filters

All filters declared in the config.json file of your Node.ACS application may be declared as an Arrow Block module that can be assigned to the before property in the definition file of an Arrow Model or API.

Websockets

For all websockets declared in the config.json file of your Node.ACS application, you will need to add an event listener to the socket once a connection is established, which requires socket.io to be added to the project. For details, see the “socket.io instance” section above.

Example

The config.json file defines a websocket that whenever a newChatMsg is received, the Node.ACS application executes the receiveMessage() method in the websockets/chatroom.js file.

//NodeACSProject/config.json
{
  "websockets":  [
    {"event": "newChatMsg", "callback": "chatroom#receiveMessage"}
  ]
}

To use the same websocket in Arrow, first add socket.io as described in the socket.io instance section, then add a newChatMsg event listener for the socket in the connection event listener.

//ArrowProject/app.js
 var Arrow = require('arrow'),
    server = new Arrow();
server.on('started', function () {
    // Creates a socket.io instance and attaches it to the Arrow instance
    this.io = require('socket.io')(this.server, {logger: this.logger});
    // Adds a connection listener 
    this.io.on('connection', function(socket) {
        socket.on('newChatMsg', function(data) {
            // Add the receiveMessage() logic here from websockets/chatroom.js
        });
    });
});
// start the server
server.start(); 

Controllers Folder

All logic declared in the Node.ACS controllers should be moved to the Arrow Route module in the web/routes folder of the Arrow project or Arrow API module. For details, see the config.json section above.

Filters Folder

All logic declared in the Node.ACS filters should be moved to the Arrow Block module.

Websockets Folder

All logic declared in Node.ACS websockets will need to be declared with the socket event listener, which requires socket.io to be added to the project. For details, see the config.json section above.

Public Folder

Copy all files in the public folder of your Node.ACS application to the web/public folder in the new Arrow project.

Views Folder

Copy all files in the views folder of your Node.ACS application to the web/views folder in the new Arrow project.

Arrow also supports other template engines including Handlebars, Markdown and ReactJS.

Run the Arrow project

After you have made your changes, to test the project, run or publish the Arrow project. To run the Arrow project locally, execute the following command from the project’s directory:

//appc run

Publish the Arrow project

To publish the Arrow project to the cloud, execute the following command from the project’s directory:

//appc publish

This will produce a new URL, different from that of your existing Node.ACS project. Follow the instructions in the Node.ACS section of the platform migration page to replace your existing Node.ACS project and update clients that use it.