Getting Started with Bluemix and Kinetise integration

This tutorial will show you how to integrate Bluemix with Kinetise. During the course of this guide, you will use the default Kinetise template to quickly build a mobile application for a restaurant.

Every restaurant app needs a menu feature. The standard Restaurant template includes one as standard, and uses a webbrowser widget to link to a static web page or document. However, Kinetise also offers another concept called a data feed. It is a powerful feature that lets you present and structure any type of data inside your Kinetised app, such as an RSS feed or served xml. Complete guidelines are available in the Kinetise Help Center.

The tutorial will show you how to serve data feeds using Bluemix, and how to use those feeds inside the Kinetised app. It will present two ways of serving the feed:

  • Using static data.
  • Using dynamically fetched data coming from SQL Database component.

When you've finished the tutorial, you'll have a working application with a menu that resembles the following:

Tutorial result

Setting up the Bluemix environment

During this step we will set up the environment that is going to be used for serving data feeds. To perform this step you have to own a valid Bluemix service account. Log in to Bluemix and head to the Dashboard. If you have not created any Bluemix applications yet, the dashboard will be empty.

Empty Dashboard

Click on the Create App tile under Cloud Foundry. This allows you to configure a new Node.js instance.

Create App Button

When the application type prompt appears, click on the Web tile.

Web

On the next screen select SDK for Node.js™ bubble. A white panel should appear. Select Continue to proceed.

SDK for NodeJS Continue

You will be prompted to provide a name for the application. For the course of this tutorial we will use AlterAPIService. When you are done with input, click on the Finish button.

Application Name

Voila! The Bluemix app has been created. You can now start implementing the static feed feature. However, since our ultimate goal is to serve dynamic feeds, this tutorial will show you how to create a database service first. Skip to the next section if you do not want to create a dynamic feed.

To create a database service, head back to the Dashboard. This time click the Use Services or APIs tile under Services & APIs.

Use Services or APIs button

Scroll down to Data Management section. Click on the SQL Database hexagon.

SQL Database Service

In the next window enter an appropriate Service name. For the course of this tutorial we will use the name AlterAPISQLDatabase. Select the Leave unbound option under the App section. When you are done, click on the Create button to proceed.

Provide Service Details

Head back to the Dashboard. You should now see your application on top of the service you have just added. Click on your app tile to view its details.

View Application Details

Next, you need to bind the database service to the application. Click the Bind a Service or API button in the center of the screen.

Click Bind a Service or API Tile

A pop-up window appears so that you can select the service. Choose the AlterAPISQLDatabase service and confirm the selection by clicking on the Add button.

Add Database Service to the Application

You will be prompted to restage the application. Confirm the operation by clicking on the Restage button.

Restage Application

You have finished setting up the Bluemix environment, congratulations! Now you can jump straight to implementing the data feed feature.

Serving static data feed

To create the menu we will use two item types:

  • Category - groups dishes, for example Pizza, Drinks and so on.
  • Entry - describes a single dish with some useful info:
    • name,
    • price,
    • image.

We have created a sample feed so that you can proceed with the implementation faster. It is presented below.

<rss xmlns:k="http://kinetise.com">
    <channel>
        <item>
            <type><![CDATA[ Category ]]></type>
            <name><![CDATA[ Pizza ]]></name>
        </item>
        <item>
            <type><![CDATA[ Entry ]]></type>
            <name><![CDATA[ Margherita ]]></name>
            <price><![CDATA[ 16.00$ ]]></price>
            <image>https://s-media-cache-ak0.pinimg.com/736x/72/d1/24/72d1241c833e00aedcfa2e532c81c1bc.jpg</image>
        </item>
        <item>
            <type><![CDATA[ Entry ]]></type>
            <name><![CDATA[ Pepperoni ]]></name>
            <price><![CDATA[ 20.00$ ]]></price>
            <image>http://www.silviocicchi.com/pizzachef/wp-content/uploads/2015/02/p3.jpeg</image>
        </item>
        <item>
            <type><![CDATA[ Entry ]]></type>
            <name><![CDATA[ Hawaiaan ]]></name>
            <price><![CDATA[ 24.00$ ]]></price>
            <image>https://somefoodsareok.files.wordpress.com/2013/07/hawaiian-pizza1.jpg</image>
        </item>
        <item>
            <type><![CDATA[ Category ]]></type>
            <name><![CDATA[ Drink ]]></name>
        </item>
        <item>
            <type><![CDATA[ Entry ]]></type>
            <name><![CDATA[ Caffe Latte ]]></name>
            <price><![CDATA[ 8.00$ ]]></price>
            <image>http://www.minimoka.es/wp-content/uploads/2012/07/caffe_latte.jpg</image>
        </item>
        <item>
            <type><![CDATA[ Entry ]]></type>
            <name><![CDATA[ Orange Juice ]]></name>
            <price><![CDATA[ 5.00$ ]]></price>
            <image>http://vid.alarabiya.net/images/2013/11/06/b8a369a5-9cab-46b8-b44b-9eda8c765236/b8a369a5-9cab-46b8-b44b-9eda8c765236_4x3_690x515.jpg</image>
        </item>
    </channel>
</rss>

To serve this feed from Node.js you need to download some starter source code first. To do this, go to the application's dashboard and select Start Coding from the left-hand side menu.

Start Coding

From there you can download the starter code by clicking Download Started Code button.

Download Starter Code

Extract the archive and open the directory with its contents. Create a new file called alter_api_response.xml in the directory where the sample app.js resides. Open the newly created file, paste the sample feed there, then save it.

Now we are going to add the service that returns the feed. Open the code located in the app.js file. Add the requirement for fs in the top of the source. fs is a module that will let us read files from the local storage.

var fs = require('fs');

Locate express framework initialization. It should look like this:

var app = express();

Create a placeholder for your new static-menu service below:

app.get('/static-menu/', function(req, res) {
    // the feed returning logic goes here
});

Then implement the simple logic that returns the feed:

fs.readFile('alter_api_feed.xml', 'utf8', function(err, data) {
    if (!err) {
        // it is important to set Content-Type properly!
        res.set('Content-Type', 'text/xml');
        res.send(data);
    }
    else {
        console.log('alter_api_feed.xml file not found!');
        res.status(500).send('Server could not provide feed!');
    }
});

Now deploy the application to Bluemix. To do this, open a terminal and type the following commands:

# 1. Change directory to the parent of app.js file
cd directory_with_app_js
# 2. Connect to Bluemix
cf api https://api.ng.bluemix.net
# 3. Login to Bluemix
cf login -u $(user_goes_here) -o $(organization_goes_here) -s $(space_name_goes_here)
# 4. Push the app
cf push AlterAPIService

After deploying the service, open the https://<your_bluemix_host>/static-menu URL in your browser. You should see the contents of the alter_api_response.xml file. That means that the back-end side is working, which means we can now create a Kinetise app to display the feed contents!

Creating a Kinetise app

Having the feed served, you can now proceed to the Kinetise webpage to create an app that consumes the feed.

To make it easier to follow this tutorial we have prepared a simple app which you can use as a foundation. To start with this sample please follow restaurant app sample URL.

Select Menu from the left-hand side menu with screens. The template default screen will appear. It should be composed of single Web Browser component like the one below.

Default menu screen

Click the browser with your left mouse button. A menu should appear above the component. Click the trash icon to delete the widget, and confirm by clicking green OK button on the pop-up.

Delete the browser and confirm it

Now locate the data feed item on the toolbar below. Drag and drop it to the screen.

Data feed icon Result of dragging feed to the screen
Data Feed icon Result of dragging feed to the screen

Next, you need to copy the proper URL of the feed into the field labelled Enter XML or JSON data feed URL here. Please note that the URL is https://<your_bluemix_host>/static-menu and was generated in the previous section. Click the green OK button next to the field. The result is shown below. Do not worry about the Node not found labels yet.

Paste the feed URL

Let's convert the data feed to use Item Templates. You can learn more about the concept in video tutorial provided by the Kinetise team. First, you have to check the Item Templates field. Then you need two add two templates: one for categories and one for entries. Do this by pressing the orange Add button.

Convert feed to Item Templates

Provide the name for the categories template. We will stick with Category for this tutorial. From the Field Name dropdown select Type and type Category in the Equals to field. Finally, select Text from the Filter combo box. Your template's configuration should resemble the following screenshot. Press the orange ADD NEW RULE button.

Configure Category template

Now save the template by clicking the blue Save button.

Save the template configuration

Repeat the steps for entries. This time specify Entry for both the Name and Equals to fields. When you have finished configuring entries, uncheck the Use default template option.

Uncheck Use default template option

In the Settings window, select the Category template, then left-click on the phone screen item marked Template. Left click on the image and choose the trashcan icon from the menu. Confirm by clicking green OK button. Do the same with the subtitle. You will be left with the following result.

Delete icon and subtitle

Now click on the title, and in the Settings list, select name from the Text dropdown. Next, click on the whole cell and select the Common tab. In the Size group set the widget height to equal 15. The result is presented below.

Set title and reduce category's height

Now click on the whole feed and select the Entry item template. Mark the title and bind it to name by selecting the appropriate value in the Text dropdown. Repeat the same steps to bind subtitle to price and image to the image node. When you've done this, select the whole data feed widget and set the value of Count field to 7, under Items group.

Set items count

That's it! You have now implemented your own menu. Click the hand icon in the bottom toolbar to preview the application.

Preview icon Resulting application
Preview icon Resulting application

Obviously our menu is a static file at the moment. We are going to convert it so that it is constructed dynamically from the database data.

Populating sample database

The first step to implementing a dynamically served feed is to create the database tables. We will use two entities:

  • MENU_CATEGORY describes group of dishes. It has two fields: a unique identifier (ID) and a name (NAME).
  • MENU_ENTRY describes a single dish. It has an identifier (ID), name (NAME), price (PRICE) and URL to the image (IMAGE). One dish is grouped inside a single category, so it has to posses CATEGORY_ID foreign key also.

We will use SQL scripts to create the schema and populate the test data. To obtain connection credentials, head to your application's dashboard and click Show Credentials on the SQL database tile.

Obtain Credentials

Use the selected DB2 client to connect to the database. We've used DBeaver for the purpose. Execute the following script against the database to create proper tables:

CREATE TABLE MENU_CATEGORY (
    CATEGORY_ID INT             NOT NULL,
    NAME        VARCHAR(128)    NOT NULL,
    PRIMARY KEY (CATEGORY_ID)
);

CREATE TABLE MENU_ENTRY (
    ENTRY_ID    INT             NOT NULL,
    NAME        VARCHAR(128)    NOT NULL,
    PRICE       DECIMAL(5,2)    NOT NULL,
    IMAGE       VARCHAR(512)    NOT NULL,
    CATEGORY_ID INT             NOT NULL,
    FOREIGN KEY (CATEGORY_ID)
        REFERENCES MENU_CATEGORY (CATEGORY_ID)
        ON DELETE RESTRICT
);

To be able to serve the feed, we also need some test data. You can populate it easily using the script presented below. It mimics the data contained within the static feed we have exposed previously.

INSERT INTO MENU_CATEGORY (CATEGORY_ID, NAME) VALUES
    (1, 'Pizza'), (2, 'Drinks');

INSERT INTO MENU_ENTRY (ENTRY_ID, NAME, PRICE, IMAGE, CATEGORY_ID) VALUES
    (1, 'Margherita', 16.00, 'https://s-media-cache-ak0.pinimg.com/736x/72/d1/24/72d1241c833e00aedcfa2e532c81c1bc.jpg', 1),
    (2, 'Pepperoni', 20.00, 'http://www.silviocicchi.com/pizzachef/wp-content/uploads/2015/02/p3.jpeg', 1),
    (3, 'Hawaiaan', 24.00, 'https://somefoodsareok.files.wordpress.com/2013/07/hawaiian-pizza1.jpg', 1),
    (4, 'Caffe Latte', 8.00, 'http://www.minimoka.es/wp-content/uploads/2012/07/caffe_latte.jpg', 2),
    (5, 'Orange Juice', 5.00, 'http://vid.alarabiya.net/images/2013/11/06/b8a369a5-9cab-46b8-b44b-9eda8c765236/b8a369a5-9cab-46b8-b44b-9eda8c765236_4x3_690x515.jpg', 2);

Now we need to handle fetching the data within Node.js app. The first step is to add a new dependency in the package.json file. To be able to communicate with DB2 database we need to use the ibm_db connector.

{
    // ...
    "dependencies": {
        // ...
        "ibm_db": "*",
    },
}

The next step is to implement database connection. Let's add a requirement for ibm_db on top of the app.js file first.

var db = require('ibm_db');

We then need to obtain credentials to connect to DB2. Provided the service was bound correctly, they will be present in the process.env.VCAP_SERVICES environment variable. You can extract them using the following snippet:

if (process.env.VCAP_SERVICES) {
    var env = JSON.parse(process.env.VCAP_SERVICES);
    db2 = env['sqldb'][0].credentials;
}
else {
    console.error("DB2 credentials not found");
}

To connect to the DB2 database using ibm_db you need a connection string. Constructing it from credentials is pretty straightforward:

var dbConnection = "DRIVER={DB2};DATABASE=" + db2.db + ";UID=" + db2.username + ";PWD=" + db2.password + ";HOSTNAME=" + db2.hostname + ";port=" + db2.port;

With the connection string, we can implement the method that executes an arbitrary fetch query on the DB2 instance. Example implementation of fetchFromDB method uses async callback to notify whether the data was extracted correctly.

function fetchFromDB(query, fetch_handler) {
    db.open(dbConnection, function(err, conn) {
        if (err) {
            console.log(err);
            fetch_handler(err, undefined);
        } else {
            conn.query(query, function(err, data) {
                if (err) {
                    console.log(err);
                    fetch_handler(err, undefined);
                } else {
                    conn.close();
                    fetch_handler(err, data);
                }
            });
        }
    });
}

To be able to expose the data to Kinetise, you also need to have a feed generation method. Our sample implementation is built on top of the xmlbuilder-js library. You need to specify explicitly that you are using this library in the package.json file.

{
    // ...
    "dependencies": {
        // ...
        "xmlbuilder": "*",
    },
}

You can now implement the feed generation method. The method will take two parameters - lists of all categories and all entries - and output the data feed in an AlterAPI-compatible format.

function generateFeed(categories, entries) {
    var doc = builder.create('rss', {'version': '1.0', 'encoding': 'UTF-8'}).att('xmlns:k', 'http://kinetise.com');
    var channel = doc.ele('channel');

    for (var i = 0; i < categories.length; ++i) {
        var item = channel.ele('item', {'k:context': 'cat_' + categories[i].CATEGORY_ID });
        item.ele('type', {}, 'Category');
        item.ele('name').dat(categories[i].NAME);

        var categoryEntries = entries.filter(function(e){ return e.CATEGORY_ID === categories[i].CATEGORY_ID; });

        for (var j = 0; j < categoryEntries.length; ++j) {
            var item = channel.ele('item', {'k:context': 'ent_' + categoryEntries[j].ENTRY_ID });
            item.ele('type', {}, 'Entry');
            item.ele('name').dat(categoryEntries[j].NAME);
            item.ele('price').dat(categoryEntries[j].PRICE + ' $');

            if (categoryEntries[j].IMAGE) {
                item.ele('image', {}, categoryEntries[j].IMAGE);
            }
        }
    }

    return doc.end({ pretty: true });
}

The last step is to glue fetchFromDB and generateFeed methods together in the form of a service. A sample implementation is presented below:

app.get('/menu/', function(req, res) {
    fetchFromDB('SELECT * FROM MENU_CATEGORY', function(err, data) {
        if (!err) {
            var categories = data;

            fetchFromDB('SELECT * FROM MENU_ENTRY', function(err, data) {
                if (!err) {
                    var entries = data;

                    if (!categories || !entries) {
                        handleError(err, req, res);
                    }

                    res.set('Content-Type', 'text/xml');
                    res.send(generateFeed(categories, entries));
                } else {
                    handleError(err, req, res);
                }
            });
        } else {
            handleError(err, req, res);
        }
    });
});

function handleError(err, req, res) {
    res.status(500).send('Server could not provide feed!');
}

Deploy the application and visit https://<your_bluemix_host>/menu in your browser. You should see the following output:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:k="http://kinetise.com">
  <channel>
    <item k:context="cat_1">
      <type>Category</type>
      <name>
        <![CDATA[Pizza]]>
      </name>
    </item>
    <item k:context="ent_1">
      <type>Entry</type>
      <name>
        <![CDATA[Margherita]]>
      </name>
      <price>
        <![CDATA[16.00 $]]>
      </price>
      <image>https://s-media-cache-ak0.pinimg.com/736x/72/d1/24/72d1241c833e00aedcfa2e532c81c1bc.jpg</image>
    </item>
    <item k:context="ent_2">
      <type>Entry</type>
      <name>
        <![CDATA[Pepperoni]]>
      </name>
      <price>
        <![CDATA[20.00 $]]>
      </price>
      <image>http://www.silviocicchi.com/pizzachef/wp-content/uploads/2015/02/p3.jpeg</image>
    </item>
    <item k:context="ent_3">
      <type>Entry</type>
      <name>
        <![CDATA[Hawaiaan]]>
      </name>
      <price>
        <![CDATA[24.00 $]]>
      </price>
      <image>https://somefoodsareok.files.wordpress.com/2013/07/hawaiian-pizza1.jpg</image>
    </item>
    <item k:context="cat_2">
      <type>Category</type>
      <name>
        <![CDATA[Drinks]]>
      </name>
    </item>
    <item k:context="ent_4">
      <type>Entry</type>
      <name>
        <![CDATA[Caffe Latte]]>
      </name>
      <price>
        <![CDATA[8.00 $]]>
      </price>
      <image>http://www.minimoka.es/wp-content/uploads/2012/07/caffe_latte.jpg</image>
    </item>
    <item k:context="ent_5">
      <type>Entry</type>
      <name>
        <![CDATA[Orange Juice]]>
      </name>
      <price>
        <![CDATA[5.00 $]]>
      </price>
      <image>http://vid.alarabiya.net/images/2013/11/06/b8a369a5-9cab-46b8-b44b-9eda8c765236/b8a369a5-9cab-46b8-b44b-9eda8c765236_4x3_690x515.jpg</image>
    </item>
  </channel>
</rss>

Link to the new URL in your Kinetise application's datafeed widget, and enjoy your restaurant's menu, dynamically served!

Summary

By following this tutorial you have learned how to feed your Kinetise app with data served from the Bluemix platform. You can obtain the complete source code at GitHub.

For further reference, please consult the Kinetise Helpcenter and Bluemix Docs. Thanks for using Kinetise!