Build a Fitness App using IBM Watson Data Platform and 3rd Party Fitness APIs

Build a Fitness App using IBM Watson Data Platform and 3rd Party Fitness APIs

Share this post:

Fitness App Steps

Taking a Stand Against a Sedentary Lifestyle

We all know that inactive lifestyles negatively impact our health. In her recent post, 8 Million Steps and Counting, Jane Rajah discussed how our knowledge of the health risks of desk jobs and a desire to motivate our coworkers inspired our team to build a Fitness App.

It took us just 5 days (and fewer than 2,000 lines of code) to build the app, using services and solutions available on the IBM Cloud. Once it was finished, we shared it with our coworkers across IBM, and today, employees in more than 15 countries are using our app to track daily steps and fitness goals.

In-app dashboards enable us to analyze and visualize the user activity data, including weight loss, overall steps, and leaderboards. We have even incorporated a third-party API to make recommendations (based on user data) about local fitness activities that they may enjoy.

Employees equipped with wearable technology reported an 8.5% increase in productivity and a 3.5% increase in job satisfaction, so we’re excited that our app is helping to keep our coworkers healthy, happy, and on the move!

 

Create Your Own Fitness App

In this post, I’ll share technical details and code samples to help you to create your very own Fitness App solution. If you want to further customize it or add specialized features, you can also go ahead and connect it to other services and APIs (like we did with the location mapping API).

Before we begin, we need to make sure your environment is set up and that you have the proper tools/keys. (But if you want to jump straight in, you can view the code on GitHub.)

 

Basic Fitness App Architecture

Fitness App Architecture

 

Let’s Get Started

Here are the services and solutions you’ll need to provision before we can begin:

 

Step 1: Bluemix

Create a Bluemix trial account.

The other services used to create the app will all be provisioned and managed within the Bluemix environment. We recommend that you use the standard plan to see ultimate performance benefits.

 

Step 2: Node.js

Once logged into your Bluemix account, provision the Node.js Cloud Foundry app.

This is how we’ll host your app.

 

Step 3: Cloudant

Next, provision the IBM Cloudant NoSQL database.

Cloudant will be used to store persistent data, such as user steps and relative weight.

 

Step 4: Data Science Experience

Then, provision the Data Science Experience (DSX).

DSX will analyze stored datasets and display the data in a graph format.

 

Step 5: Fitbit

Register your Fitbit application.

 

Setup your .env file

CLOUDANT_ACCOUNT=cloudantAccount
CLOUDANT_KEY=cloudantKey
CLOUDANT_PASSWORD=cloudantPassword

Register Fitbit Users

In order for us to pull data from Fitbit, we first need to setup a callback endpoint for Fitbit OAuth. Once you’ve created your SDK for Node.js app, you should have a FQDN from Bluemix. (http://bit.ly/2wmTtn3).

Next, we will need to create an express server with an endpoint to handle the OAuth callback from Fitbit.

app.js

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    import express from "express";
    import bodyParser from "body-parser";
    import Scheduler from "./scheduler";
    import path from "path";
    import cfenv from "cfenv";
    import { logger } from "./logger";

    import home from "./controllers/home";
    import fitbit from "./controllers/fitbit";
    import registered from "./controllers/registered";

    const schedule = new Scheduler();
    let app = new express();

    // Middleware to handle application/json and application/x-www-form-urlencoded
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.set("views", path.join(__dirname, "public"));

    app.set("view engine","ejs");

    app.use(express.static(__dirname + "/public"));
    // Middleware routes
    app.use("/", home);
    app.use("/fitbit", fitbit);
    app.use("/registered", registered);

    const appEnv = cfenv.getAppEnv();
    const PORT = appEnv.port || 3000;

    // Start scheduler that handles jobs.
    schedule.start();

    // start server on the specified port and binding host
    app.listen(PORT, "0.0.0.0", function() {
        logger.log("info","server starting on " + appEnv.url);
    });

 

Add Persistence Using Cloudant

When a user registers with our application, we want to make sure we are persisting their access_token and refresh_token so we can pull the user’s data later on. To do this, we will use Cloudant on IBM Bluemix. But before we can write code to insert data into Cloudant, we need to create the databases.

Launch the Cloudant dashboard and create a weight, steps, and users database. (If you are unsure on how to create a database, you can view the documentation here.) You will also want to create an index to optimize query lookup, which can also be found in the documentation. We will now create a wrapper around the Cloudant client to handle persisting steps, weights, and user’s data into our Cloudant database.

cloudant.js

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    import cloudant from "cloudant";
    import Promise from "bluebird";

    export default class Cloudant {
        /**
         * Creates a cloudant db connection.
         * @constructor
        */
        constructor() {
            this.cloudant = new cloudant({ account: process.env.CLOUDANT_ACCOUNT, key: process.env.CLOUDANT_API_KEY, password: process.env.CLOUDANT_PASSWORD });
            this.mass_db = this.cloudant.db.use("weight");
            this.user_db = this.cloudant.db.use("users");
            this.steps_db = this.cloudant.db.use("steps");
        }

        /**
         * Returns all users registered.
         * @returns {Array} All users registered in the db.
         */
        getAllUsers() {
            return new Promise((resolve,reject) => {
                this.user_db.list({ include_docs:true }, (err, data) => {
                    if(err) reject(err);

                    resolve(data.rows);
                });
            });
        }

        /**
         * Register user into database.
         * @param {Object} doc A formatted doc for cloudant to insert a user
         * @returns {Object} Response from cloudant.
         */
        addUser(doc) {
            return new Promise((resolve,reject) => {
                this.user_db.insert(doc, (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }

        /**
         * Retrieves a user from the database.
         * @param {Object} query A formatted query for cloudant to retrieve a user.
         * @returns {Object} Response from cloudant.
         */
        getUser(query) {
            return new Promise((resolve,reject) => {
                this.user_db.find(query, (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }

        /**
         * Retrieves a user from the database.
         * @param {Object} user A user that you want to delete from user's db
         * @returns {Object} Response from cloudant.
         */
        deleteUser(user) {
            return new Promise((resolve,reject) => {
                this.user_db.destroy(user["_id"], user["_rev"], (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }


        /**
         * Insert steps into db.
         * @param {Object} doc A formatted doc for cloudant to insert steps for a given user
         * @returns {Object} Response from cloudant.
         */
        insertSteps(doc) {
            return new Promise((resolve,reject) => {
                this.steps_db.insert(doc, (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }

        /**
         * Delete steps from steps db.
         * @param {Object} doc A formatted doc for cloudant to insert steps for a given user
         * @returns {Object} Response from cloudant.
         */
        deleteSteps(doc) {
            return new Promise((resolve,reject) => {
                this.steps_db.destroy(doc["_id"], doc["_rev"], (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }

        /**
         * Insert steps in bulk into db.
         * @param {Array} docs An array of formatted doc for cloudant to insert steps for a given user
         * @returns {Object} Response from cloudant.
         */
        insertBulkSteps(docs) {
            return new Promise((resolve,reject) => {
                this.steps_db.bulk({ docs }, (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }
        /**
         * Insert weight in bulk into db.
         * @param {Array} docs An array of formatted doc for cloudant to insert weight for a given user
         * @returns {Object} Response from cloudant.
         */
        insertBulkWeight(docs) {
            return new Promise((resolve,reject) => {
                this.mass_db.bulk({ docs }, (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }


        /**
         * Returns steps for a given user.
         * @param {Object} query A formatted query for cloudant to get steps for a given user
         * @returns {Array} Returns all steps for a given user.
         */
        getSteps(query) {
            return new Promise((resolve,reject) => {
                this.steps_db.find(query, (err, data) => {
                    if(err) reject(err);
                    data = (data ? data.docs : []);
                    resolve(data);
                });
            });
        }

        /**
         * Insert weight into db.
         * @param {Object} doc A formatted doc for cloudant to insert weight for a given user
         * @returns {Object} Response from cloudant.
         */
        insertMass(doc) {
            return new Promise((resolve,reject) => {
                this.mass_db.insert(doc, (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }

        /**
         * Returns weight for a given user.
         * @param {Object} query A formatted query for cloudant to get weight for a given user
         * @returns {Array} Returns all weight for a given user.
         */
        getMass(query) {
            return new Promise((resolve,reject) => {
                this.mass_db.find(query, (err, data) => {
                    if(err) reject(err);

                    data = (data ? data.docs : []);
                    resolve(data);
                });
            });
        }

    /**
         * Delete weight doc from database
         * @param {Object} doc A formatted doc for cloudant to insert steps for a given user
         * @returns {Object} Response from cloudant.
         */
        deleteMass(doc) {
            return new Promise((resolve,reject) => {
                this.mass_db.destroy(doc["_id"], doc["_rev"], (err, data) => {
                    if(err) reject(err);

                    resolve(data);
                });
            });
        }
    }

 

Pull the Data

Next, we need to identify the type of data we want to gather. Fitbit’s API documentation showcases the different types of data that are available to you. For now, we will be collecting steps, weight and profile information. Now that we have our Cloudant library created we can start calling Fitbit’s API for the user’s steps and mass. Once we get that data, we can process the data and leverage the wrapper we created above to persist the data into Cloudant.

fitbit.js

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import Cloudant from "./cloudant.js";
import request from "request-promise";
import { logger } from "./logger";
import Throttle from "promise-throttle";

const db = new Cloudant();
const FITBIT_CLIENT_ID = process.env.FITBIT_CLIENT_ID;
const FITBIT_CLIENT_SECRET = process.env.FITBIT_CLIENT_SECRET;
const FITBIT_CLIENT_SECRET_64 = new Buffer(`${FITBIT_CLIENT_ID}:${FITBIT_CLIENT_SECRET}`).toString("base64");

export default class FitBit {

    /**
     * Get user's steps for the day.
     * @param {string} user_id The fitbit user's id.
     * @param {string} access_token The fitbit user's access_token.
     * @returns {Object} The daily steps for the requested user.
     */
    async getSteps(user_id, access_token) {
        let now = new Date();
        let start_date = new Date(new Date().setDate(now.getDate()-30)).toISOString().split("T")[0];
        let end_date = `${ now.getFullYear() }-${ ("0" + (now.getMonth()+1) ).slice(-2) }-${ ("0" + now.getDate()).slice(-2) }`;

        try {
            let results = await request({
                // Fitbit only allows you to pull 31 days of data.
                url: `https://api.fitbit.com/1/user/${user_id}/activities/steps/date/${start_date}/${end_date}.json`,
                headers: {
                    "Authorization": `Bearer  ${access_token}`
                },
            });

            if(results) {
                results = JSON.parse(results);
                return results["activities-steps"];
            }
        } catch(err) {
            logger.log("error",`Error occured getting steps from fitbit api: ${JSON.stringify(err,null,4)}`);
        }
    }

    /**
     * Get user's steps for the day.
     * @param {string} fitbit_id The fitbit user's id.
     * @param {string} access_token The fitbit user's access_token.
     * @returns {Object} The daily body_mass for the requested user.
     */
    async getMass(fitbit_id, access_token) {
        let now = new Date();
        let start_date = new Date(new Date().setDate(now.getDate()-30)).toISOString().split("T")[0];
        let end_date = `${ now.getFullYear() }-${ ("0" + (now.getMonth()+1) ).slice(-2) }-${ ("0" + now.getDate()).slice(-2) }`;

        try {
            let results = await request({
                // Fitbit only allows you to pull 31 days of data.
                url: `https://api.fitbit.com/1/user/${fitbit_id}/body/log/weight/date/${start_date}/${end_date}.json`,
                headers: {
                    "Authorization": `Bearer  ${access_token}`
                },
            });

            if(results) {
                results = JSON.parse(results);
                results = (results["weight"].length > 0 ? results["weight"] : []);
                return results;
            }
        } catch(err) {
            logger.log("error",`Error occured getting mass from fitbit api: ${JSON.stringify(err,null,4)}`);
        }
    }

    /**
     * Get user's steps for the day.
     * @param {Object} user The user which needs to be revoked.
     * @returns {void}
     */
    async revokeAccess(user) {
        try {
            let results = await request({
                url: "http://fitbit.link/2wXlw04",
                headers: {
                    "Authorization": `Basic ${FITBIT_CLIENT_SECRET_64}`
                },
                qs: { "token": user.access_token }
            });
            logger.log("debug", `Revoking user's access response ==> ${ JSON.stringify(results,null,4) }`);
        } catch(err) {
            logger.log("error",`Error occured revoking access from fitbit api: ${JSON.stringify(err,null,4)}`);
        }
    }



    /**
     * Process steps for the day
     * @param {string} name The fitbit user's id.
     * @param {string} fitbit_id The fitbit user's id.
     * @param {Array} periods The fitbit user's daily steps since begining of the pull.
     * @returns {void}
     */
    async processSteps(name, fitbit_id, periods) {
        try {
            // Cloudant lite has a 5 queries/sec limit
            const promiseThrottle = new Throttle({
                requestsPerSecond: 2,           // up to 1 request per second
                promiseImplementation: Promise  // the Promise library you are using
            });

            const getSteps = (day) => {
                return new Promise((resolve) => {
                    let query = { "selector": { "date": day.dateTime, "name": name}};
                    let docs = db.getSteps(query);
                    resolve(docs);
                });
            };

            for(let day of periods){
                // Throttle requests
                promiseThrottle.add(getSteps.bind(this, day))
                    .then(function(docs) {
                        if(docs.length > 0) {
                            let doc = docs[0];
                            // Dates are the same, check to see if the user has taken more steps then previously recorded.
                            if(doc.steps < day.value) {
                                //Update the doc here..
                                doc.steps = parseInt(day.value);
                                db.insertSteps(doc);
                            }
                        } else {
                            // Steps for the day are not in database, insert new record.
                            db.insertSteps({
                                steps: parseInt(day.value),
                                name,
                                fitbit_id,
                                date: day.dateTime
                            });
                        }
                    }).catch(e => e);
            }
        } catch(err) {
            logger.log("error",`Error occured: ${JSON.stringify(err,null,4)}`);
        }
    }

    /**
     * Process weight for the day
     * @param {string} name The fitbit user's id.
     * @param {string} fitbit_id The fitbit user's id.
     * @param {Array} periods The fitbit user's daily weight since begining of the pull.
     * @returns {void}
     */
    async processMass(name, fitbit_id, periods) {
        try {

            // Cloudant lite has a 5 queries/sec limit
            const promiseThrottle = new Throttle({
                requestsPerSecond: 2,           // up to 1 request per second
                promiseImplementation: Promise  // the Promise library you are using
            });

            const getMass = (day) => {
                return new Promise((resolve) => {
                    let query = { "selector": { "date": day.date, "name": name}};
                    let docs = db.getMass(query);
                    resolve(docs);
                });
            };

            for(let day of periods){
                promiseThrottle.add(getMass.bind(this, day))
                    .then(function(docs) {
                        if(docs.length > 0) {
                            let doc = docs[0];
                            // Dates are the same, check to see if the user's weight has changed.
                            if(doc.body_mass !== day.weight) {
                            //Update the doc here..
                                doc.body_mass = day.weight;
                                db.insertMass(doc);
                            }
                        } else {
                            // Weight for the day is not in database, insert new record.
                            db.insertMass({
                                body_mass: day.weight,
                                name,
                                fitbit_id,
                                date: day.date
                            });
                        }
                    }).catch(e => e);
            }
        } catch(err) {
            logger.log("error",`Error occured: ${JSON.stringify(err,null,4)}`);
        }
    }

    /**
     * Process data for a given user
     * @param {Object} user The fitbit user's cloudant doc
     * @returns {void}
     */
    async processData(user) {
        let name = user.doc.name;
        let fitbit_id = user.doc.fitbit_id;
        let access_token = user.doc.access_token;
        // console.log(`getting steps... name: ${name} - fit id ${fitbit_id} -- access_token ${access_token}`);
        try {
            let steps_periods = await this.getSteps(fitbit_id, access_token);

            // Processing steps to see if any updates need to happen..
            await this.processSteps(name, fitbit_id, steps_periods);

            let weight_periods = await this.getMass(fitbit_id, access_token);
            // Processing body mass to see if any updates need to happen
            await this.processMass(name, fitbit_id, weight_periods);

        } catch(err) {
            logger.log("error",`Error happened with processing data: ${JSON.stringify(err,null,4)}`);
        }
    }
}

 

 

Scheduling your data updates

Now that we have our code to handle pulling the data from Fitbit’s API and persisting into Cloudant, we need to repeat this task at a time interval to make this application more competitive.
We have set the time interval to every 30 minutes, but feel free to play around with it. We also need to handle user’s refresh token, as Fitbit’s tokens expire every 8 hours.

jobs.js

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    import Cloudant from "./cloudant.js";
    import Fitbit from "./fitbit";
    import { logger } from "./logger";
    import request from "request-promise";
    import Throttle from "promise-throttle";

    const db = new Cloudant();
    const fb = new Fitbit();
    const FITBIT_CLIENT_ID = process.env.FITBIT_CLIENT_ID;
    const FITBIT_CLIENT_SECRET = process.env.FITBIT_CLIENT_SECRET;
    const FITBIT_CLIENT_SECRET_64 = new Buffer(`${FITBIT_CLIENT_ID}:${FITBIT_CLIENT_SECRET}`).toString("base64");
    /**
     * Process that kicks off updating the user's steps and weight for the day.
     * @returns {void}
     */
    export function updateData() {
        logger.log("info","Pulling data to see if there are any changes since the last pull.");
        db.getAllUsers()
            .then((users) => {
                users.forEach((user) => {
                    // Skip the design docs.
                    if(user.doc["_id"].includes("_design")){
                        return;
                    }

                    fb.processData(user);
                });
            })
            .catch((err) => {
                logger.log("info",`There is an error pulling the users: ${ JSON.stringify(err,null,4) }`);
            });
    }

    /**
     * Process that refresh's user's access_token every 8 hours (http://fitbit.link/2wm89mK)
     * @returns {void}
     */
    export async function refreshTokens(){
        let users = await db.getAllUsers();
        users.forEach(async (user) => {
            user = user.doc;

            // Skip the design docs.
            if(user["_id"].includes("_design")){
                return;
            }

            try {
                let refreshed_ua_token = await request({
                    uri: "http://fitbit.link/2wXQpBE",
                    method: "POST",
                    headers: {
                        "Authorization": `Basic ${FITBIT_CLIENT_SECRET_64}`,
                        "Content-Type": "application/x-www-form-urlencoded"
                    },
                    form: {"grant_type": "refresh_token", "refresh_token": user.refresh_token}
                });
                // Parse response and update user's doc
                refreshed_ua_token = JSON.parse(refreshed_ua_token);
                user.refresh_token = refreshed_ua_token.refresh_token;
                user.access_token = refreshed_ua_token.access_token;

                // Insert updated user doc into cloudant.
                let updated_user = await db.addUser(user);
                if(!updated_user.ok) {
                    logger.error("There was an issue updating a user's doc in cloudant..");
                }

            } catch(err) {
                logger.log("error", `Error refreshing tokens for user ${JSON.stringify(err,null,4)}`);
            }
        });
    }

Now that we have our jobs created to refresh user’s tokens and pull data from fitbit’s API, we can now schedule them using cron npm.

scheduler.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { updateData, refreshTokens, deleteUsersData } from "./jobs.js";
import { CronJob } from "cron";
import { logger } from "./logger";

/**
 * Represents a Cron scheduler
 */
export default class Cron {
    /**
     * Starts the provided cronjobs.
     * @returns {void}
     */
    start(){
        // Refresh tokens on start, in-case app hasn't been stopped for more then 8 hours.
        logger.log("info","Refreshing tokens from fitbit...");
        refreshTokens();

        // Update all user's steps and weight every 30 minutes.
        new CronJob("0 */30 * * * *", function() {
            logger.log("info","Pulling data from fitbit...");
            updateData();
        }, null, true, "America/Los_Angeles");

        // Refresh fitbit access_token/refresh_token for all users every 5 hours.
        new CronJob("0 0 */5 * * *", function() {
            logger.log("info","Refreshing tokens from fitbit...");
            refreshTokens();
        }, null, true, "America/Los_Angeles");

        // Deletes all newly registered users data at midnight every night.
        new CronJob("0 0 12 * * *", function() {
            deleteUsersData();
        }, null, true, "America/Los_Angeles");
    }
}

 

Logging data to console

You might of noticed that in some of the code snippets we are importing a Logger and using it to print debug statements to the console. We have used the Winston npm to achieve this, which looks something like this:

logger.js

1
2
3
4
5
6
7
8
import winston from "winston";

export const logger = new (winston.Logger)({
    level: "verbose",
    transports: [
        new (winston.transports.Console)(),
    ]
});

 

Supporting ES7 Features

You might of noticed some of the new ES7 keywords, async/await. In order for us to deploy this on Bluemix, we need to tell them to use the Node.js 8.1 runtime, to do this insert this snippet into your package.json:

1
2
3
4
5
  "engines": {
      "node": "8.1.0",
      "npm": "5.0.3"
  }

 

Deploy to Bluemix!

Now that we have finished developing locally, we can deploy this application to Bluemix using the CF CLI. First ensure that you have a valid manifest.yml file in the root directory that will look something like this:

manifest.yml


1
2
3
4
5
applications:
- name: 
  command: node server.js
  random-route: false
  memory: 300M

 

Then run the following commands to deploy your application to Bluemix:

cf api http://bit.ly/2pEpvLA
cf login
cf push -f manifest.yml

 

Explore and Visualize the Data with Data Science Experience

Now that we have an application that users can sign up for, it’s time to use Data Science Experience to analyze and derive some insights from your users’ data. Duplicate the Jupyter Notebook here to explore and play around with it.

 

Enhance Your App

You just learned how to create a solution that allows you to ingest data, persist it to a data store, and analyze the data using a notebook in the Data Science Experience. You now have an application that will record and track your users’ steps and showcase who among them is getting the most activity each day!

Those are the basics, but there are many parts of the application that can be further expanded to include robust additional features.

 

  • You can use a service like IBM Streaming Analytics to sift through large amounts of incoming data and locate targeted results, such as user activity. You could then use that personalized activity data to build a user activity recommendation engine based on browser location data, which could suggest places to run, hike, or cycle.
  • Or, you can use Watson Machine Learning to create a model that will predict competition winners, which you can deploy and use inside of your Node.js application.

 

What other ways could you enhance your Fitness Application?

Let us know in the comments, and happy coding!

#awvi,#Cloud,#ibm

Bluemix

via Bluemix Blog https://ibm.co/2pQcNaA

September 11, 2017 at 09:45AM

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s