Application Integration

Appcelerator Arrow: Server Processing Example for Faster Apps

In addition to being able to easily create integrations to backend data sources, Arrow provides several facilitates for moving data manipulation and processing operations from the client app to the Arrow server. This results in a mobile app that is more performant since data manipulations and computations do not need to be performed in the app. Implementing business logic and computations on the server, instead of in the mobile app also makes changes simpler since a new app does not need to be published when business logic/rules change.

KPI and Totals Row Example

Consider a simple use case of an app for displaying actual vs forecast sales data that is retrieved from a Microsoft SQL or MySQL staging Database.

phpMyAdmin

Arrow makes this easy with it’s out of the box connectors for MS SQL, MySQL and other backends.

I created a model, SalesByRegion, based on table1 that returned the following data:

{
  "success": true,
  "request-id": "089bf3ab-8ad4-404d-a2e9-8546485817b2",
  "key": "salesbyregions",
  "salesbyregions": [
    {
      "id": 0,
      "rid": 0,
      "region": "NE",
      "act": 66,
      "fcst": 77
    },
        ...
    {
      "id": 3,
      "rid": 3,
      "region": "Cent",
      "act": 52,
      "fcst": 61
    },
    {
      "id": 4,
      "rid": 4,
      "region": "Can",
      "act": 35,
      "fcst": 71
    }
  ]
}

An example of using this API in a mobile app, is shown below.

Flash Report

Now, consider an enhancement, where you would like to display KPIs (key performance indicators) in the table indicating the sales performance of each region, using a color scheme as follows:

flashreport-2

This small enhancement makes the mobile experience better since it helps the user quickly focus on the areas of interest.

This can easily be implemented in the mobile app in client-side code by performing the necessary calculation, say by dividing the actual sales by the forecast and comparing to a threshold to determine what KPI to display. In Titanium, this could be performed in the row controller code as follows:

var p = 100*args.act/args.fcst;

if(p>Alloy.Globals.greenThreshold){
    $.kpiImageView.image = '/images/kpi_green.png';
} else if(p

However, if the threshold levels were to ever change, a new app would need to be deployed to the users. Let’s move this code to the Arrow API instead and return the computed KPI along with the sales data.

Arrow Model Custom Field

Lets add a custom field, kpi, to the MySQL or MSSQL Arrow Model as follows:

"kpi": {
  "type": "string",
  "custom": true,
  "get": function(val,key,model){
      var kpi_val;
      var p = 100*model.get('act')/model.get('fcst');
      if(p < 50) {
        kpi_val="red";
      } else if(p < 70) {
        kpi_val = "yellow";
      } else {
        kpi_val = "green";
      }
      return kpi_val;
  }
}

Now the data returned by the API looks like this:

{
  "success": true,
  "request-id": "089bf3ab-8ad4-404d-a2e9-8546485817b2",
  "key": "salesbyregions",
  "salesbyregions": [
    {
      "id": 0,
      "rid": 0,
      "region": "NE",
      "act": 66,
      "fcst": 77,
      "kpi": "green"
    },
        ...
    {
      "id": 3,
      "rid": 3,
      "region": "Cent",
      "act": 52,
      "fcst": 61,
      "kpi": "green"
    },
    {
      "id": 4,
      "rid": 4,
      "region": "Can",
      "act": 35,
      "fcst": 71,
      "kpi": "red"
    }
  ]
}

Now the client-side code simply needs to check the KPI value and set the image. No computation is required and threshold values can be modified on the Arrow server without needing to redeploy the mobile app.

Add a Totals Row

What if you wanted to add a totals row to the table, as follows:

flashreport-3

Again, you can easily do this in Titanium by looping through the rows and summing the values for actual and forecast and adding a TableView footer or a ListView footer template to display the totals row.

However, to reduce the computation on the mobile device, we can implement this in the API using an Arrow Block.

We can add the following property to the model:

"after": "addtotal",

This indicates that after the data is retrieved from the database run the block named addtotal.

addtotal.js is shown below:

var Arrow = require('arrow');
var PostBlock = Arrow.Block.extend({
    name: 'addtotal',
    description: 'add total row to sales data',
    action: function(req, resp, next) {
        var body = JSON.parse(resp.body);
        var data = body[body.key];
        var dataLen = data.length;
        var replies = 0;
        if(dataLen){ //findAll
            var actTotal=0, fcstTotal=0;
            data.forEach(function (_row, _index) {
                actTotal += _row.act;
                fcstTotal += _row.fcst;
            });
        } else { //findOne
            actTotal =data.act;
            fcstTotal = data.fcst;
        }
        resp.success({
        data: body[body.key],
        totals: {"actTotal": actTotal, "fcstTotal": fcstTotal}
        }, next);

    }
});

module.exports = PostBlock;

The code above will be executed after the data is retrieved from the database, loop through the rows and calculate a totals row, which will be added to the repy object in the resp.success() call.

resp.success({
    data: body[body.key],
    totals: {"actTotal": actTotal, "fcstTotal": fcstTotal}
}, next);

The data that the API now returns is shown below:

{
  "success": true,
  "request-id": "de51ff25-3778-4696-8c60-58bad9663e23",
  "key": "salesbyregion",
  "salesbyregion": {
    "data": [
      {
        "id": 0,
        "rid": 0,
        "region": "NE",
        "act": 66,
        "fcst": 77,
        "kpi": "green"
      },

            ...

      {
        "id": 3,
        "rid": 3,
        "region": "Cent",
        "act": 52,
        "fcst": 61,
        "kpi": "green"
      },
      {
        "id": 4,
        "rid": 4,
        "region": "Can",
        "act": 35,
        "fcst": 71,
        "kpi": "red"
      }
    ],
    "totals": {
      "actTotal": 220,
      "fcstTotal": 298
    }
  }
}

Summary

In this example, we saw how Arrow can be used to create highly specific and mobile optimized APIs that reduce the computational complexity of the mobile app and reduce the need to deploy new app versions as business rules/logic change.

Code for this example can be found here and you can read more about Arrow here.