Chapter 1. Developing Cloud Apps

1.1. Cloud Development

1.1.1. Overview

One of the core concepts in the Red Hat Mobile Application Platform (RHMAP) are Cloud Apps — server-side applications which handle communication between Client Apps deployed on mobile devices, and back-end systems which contain business logic and data.

Cloud apps are developed using Node.js — a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

For those not familiar with Node.js development, the Node Beginner Website is an excellent resource.

1.1.2. Cloud App Structure

When a Cloud App is created in RHMAP, this newly created Cloud App is essentially a pre-configured Node.js application. If a corresponding pre-configured Client App is also generated, the Cloud App will include all basic configuration (routes) so that the Client and Cloud App are in sync. In addition, the infrastructure for hosting the Cloud App is also in place (MBaaS) and is easily accessible.

As the configuration and infrastructure are all in place, the Cloud App can be deployed to an MBaaS and is capable of routing the Client App’s requests without the need of additional code. Should an advanced Node.js developer wish to re-engineer the server or implement their own server, this is possible through the manipulation of the code within the application.js file.

Note

Ensure that the file that represents the main entry point to your App is always called application.js.

The following files are provided by default in a Cloud App:

1.1.2.1. application.js

This file is invoked when your application is deployed to an MBaaS - our cloud execution environment. In most cases you will not need to touch this file - it is set to handle fh.cloud() requests from the client and route them accordingly.

1.1.2.2. package.json

The configuration file for your Cloud App is primarily used for dependency management. If you are using third-party Node modules, they will be specified in this file.

See also:

1.1.3. Example

There are only a few steps to get a Cloud App running. You can explore a simple example by trying the Hello World Project template when creating a new project in the Studio, or by looking at the source code of the template on GitHub: feedhenry-templates/helloworld-cloud. This is a brief overview of the template.

The first step is to configure a custom route in application.js:

app.use('/hello', require('./lib/hello.js')());

In the referenced hello.js file, you would define the logic for that particular route.

var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');

function helloRoute() {
  var hello = new express.Router();
  hello.use(cors()); // enables cross-origin access from all domains
  hello.use(bodyParser()); // parses POST request data into a JS object

  hello.post('/', function(req, res) {
    res.json({msg: 'Hello ' + req.body.hello});
  });
  return hello;
}
module.exports = helloRoute;

The client-side call to this endpoint using $fh.cloud might look like the following:

$fh.cloud({
    path: 'hello',
    data: {
      hello: 'World'
    }
  },
  function (res) {
    // response handler
  },
  function (code, errorprops, params) {
    // error handler
  }
);

1.2. Environments

1.2.1. What are Environments

Environments are a way of logically separating the development cycles of Projects, Services, Forms and Apps into discrete stages. Environments are a key part of Lifecycle Management.

For example, a Project could have 3 stages of development: Dev, UAT & Production. Each stage is represented by an Environment. The number and make up of Environments is configurable through the Platform and can be tailored on a per-domain basis.

1.2.2. How Environments interact with Business Objects

Below is a quick reference for identifying areas in the App Studio where Environments are utilised

  • Projects (including Apps)
  • Services
  • Forms
  • Admin > Auth Policies

Should you access these areas without access to any Environments, you will see a warning similar to the one below:

Core Structure

1.2.3. No Environments — reduced functionality

To perform most actions relating to Projects, Services, Forms and Apps in the App Studio, you will need to be able to access one or more Environments.

If you are currently unable to access any Environments, this could be because:

  • Your current Team membership excludes you from utilising any Environments
  • Your Administrator has not setup any Environments yet

1.2.3.1. Update Team Membership

To gain access to an Environment you (or an Administrator for your Domain) will need to:

  • Navigate to the Admin > Teams area
  • Alter a team you are a member of and grant members of this team access to the Admin > Environment business object

For more details about administering Teams, see here.

1.2.3.2. Administrator Environment Setup

If you believe your Team setup and membership is correct, contact your local Administrator for further assistance. Environments need to be set up by an Administrator before access to them can be granted via Teams.

1.2.4. Other resources

1.3. Using Node.js Modules in Cloud Apps

1.3.1. Overview

This guide shows you how to include and use Node.js modules in your Cloud Apps. In the Red Hat Mobile Application Platform (RHMAP), you can use the modules of any Node.js package available in the registry to develop your Cloud Apps. In the public registry - npmjs.com - you can find thousands of packages - frameworks, connectors, and various tools.

NPM website

Parts of functionality of RHMAP itself are exposed as node modules. For example, when you create a new Cloud App on the Platform, by default the package.json will include a node module called fh-mbaas-api, which is the cornerstone of the Mobile Backend As A Service (MBaaS) in RHMAP.

1.3.2. Getting Started with Node.js Modules

If you need a piece of functionality in your app and you don’t want to reinvent the wheel, it’s worth searching for existing modules on npmjs.com.

For example, if you want to use the Mongoose ODM framework, you can try looking at the official page of the mongoose package in the registry - npmjs.com/package/mongoose.

npmjs.com Mongoose package detail

To use the latest version of the package in your project, running the following command in your Cloud App’s directory will install the package locally and add it as a dependency to the package.json file of your Cloud App:

npm install --save mongoose

Alternatively, you can add the dependency to package.json manually, by appending it at the end of the dependencies object, as in the following example:

{
    "name": "my-fh-app",
    "version": "0.2.0",
    "dependencies": {
        "body-parser": "~1.0.2",
        "cors": "~2.2.0",
        "express": "~4.0.0",
        "fh-mbaas-api": "~4.9.0",
        "mocha": "^2.1.0",
        "request": "~2.40.0",
        "mongoose": "~4.1.12" // added mongoose dependency
    }
}

At this point, you can start using the modules provided by the package. Often, the package page on npmjs.com contains instructions for usage and links to documentation. The next step common to all modules is requiring the module in your code to be able to use it:

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_database');
...

In this example, the database URL is hard-coded in the source. A more common scenario, however, is using different databases for different stages of development life cycle - development, testing, production. This can be resolved by defining configuration values through environment variables.

1.3.3. Environment Variables

If any part of the configuration of your Cloud App - such as hostnames, usernames, or passwords - varies between life cycle stages, you can set such configuration values using environment variables. That allows you to make configuration changes without changing the code. Every Cloud App has an Environment Variables section in the Studio where you can create or remove variables, set values, or push the variables to a running instance of the app.

Environment variables

Environment variables are especially useful in combination with the ability to push different values to different environments. For example, you could be using a different database host for testing and for production. Another benefit is that sensitive configuration information can be stored outside of the code base of your application.

In a Cloud App, environment variables can be accessed through the process.env object. The previous example of a Mongoose connect call changed to use environment variables would look this way:

mongoose.connect('mongodb://' + process.env.MONGO_HOST + '/' + process.env.MONGO_DB);

1.4. Node.js Dependency Management Using npm

1.4.1. Overview

npm, the node package manager, is a dependency management tool for Node.js and is an integral part of developing any Node.js application. In its principles, npm is similar to any other dependency management system, like Maven, Cocoapods, or NuGet:

  • projects declare dependencies in a standardized file - package.json in case of Node.js;
  • packages are hosted in a central location - the npm registry at registry.npmjs.org;
  • dependency versions can be specified explicitly, or using wildcards or ranges;
  • versions of transitive dependencies can be decided automatically, or fixed (see Using an npm-shrinkwrap file);
  • packages are cached locally after installation (node_modules folder).

For an introduction to using Node.js modules in your Cloud Apps, see Using Node.js modules in Cloud Apps.

1.4.2. npm and App Staging

When deploying your Cloud App, the npm command is run in your app’s environment, to download and install the dependencies of your app. Note the following:

  • The first time your Cloud App is deployed, a full npm install is done. Because of this, the first deployment of your app can be quite slow.
  • Each subsequent deploy, if the package.json file has changed from the previous deploy, an npm update is run.
  • If no changes have been made to package.json, no npm command is run (neither update, nor install).
  • To re-run npm fully, do a clean stage as follows:

    • In the Studio, check the Clean Stage check box in the Deploy section of the Cloud App
    • If using fhc, use the --clean option, that is, fhc app stage <app-id> <env-name> --clean

1.4.3. npm Best Practices

The fundamental best practice with npm is to understand how versioning works with node modules (see The semantic versioner for npm) and to avoid using * for any dependencies in package.json.

A handy tip for developing locally is to use the --save flag when installing a module using npm, for example, npm install request --save. The --save flag will append the new module to the dependencies section in your package.json with the version that has just been installed. We also recommend using a shrinkwrap file.

1.4.3.1. Using an npm-shrinkwrap file

An npm-shrinkwrap.json file locks down the versions of a package’s transitive dependencies so that you can control exactly which versions of each dependency will be used when your package is installed.

To create a shrinkwrap file, run:

npm shrinkwrap

Put the resulting npm-shrinkwrap.json file to the root directory of your Cloud App. When npm install is invoked on your app in RHMAP, it will use exactly the versions defined in the shrinkwrap file.

To learn more about shrinkwrap, see the official npm documentation - Lock down dependency versions.

1.4.4. Uploading node_modules

RHMAP allows you to commit your node_modules directory and to use this in your Cloud App, even though it’s not a recommended practice. That way, npm is not run at all when your app is staged (even if the clean option is specified), and whatever modules you’ve uploaded will be used to run your app. However, native node modules need to be compiled on the same architecture on which they execute, which might vary between instances of RHMAP.

1.5. Setting the Node.js version

1.5.1. Using fhc

Firstly ensure you have the latest version of fhc.

npm install -g fh-fhc

You can then use the fhc runtimes command to see which runtimes are available to you in an Environment.

fhc runtimes --env=dev

This command will output the version, for example, 4.4.7.

On the left is the name of the runtime and on the right is the particular version.

fhc app stage --app=<APP_GUID> --runtime=<node version>

To set the app’s runtime during a stage, add the <node version>, for example, 4.4.7.

This will set your apps runtime to v4.4.7 of node.

To change it to a different runtime, add the runtime argument to the stage command again

1.5.2. Using the studio

In the Studio from the deploy screen you can see the current runtime the app is set to. You can also set a new runtime here and then deploy your app.