Appcelerator Blog

The Leading Resource for All Things Mobile

Appcelerator Arrow Builder—Multiple Post Blocks Salesforce/Geocode/Foursquare Example

1 Flares 1 Flares ×

In a prior post, I described how Arrow’s Block feature can be leveraged to enhance data retrieved from Salesforce to geocode the data. The sales reps that are using the mobile app are now able to map their accounts as part of their prospecting and get turn-by-turn directions without having to copy and paste or manually switch between apps. Many of the sales reps asked if there was a way to see restaurants or coffee shops near the account they are visiting so that when they plan their client visit they can suggest a place to meet. In this blog post, we’ll extend our last example and add a second block that will take the Salesforce account data that now has geocode information and use the Foursquare API to also get coffee shops that are near the customer. This is commonly referred to as a data mashup. The diagram below helps to illustrate the data flow for our aggregated API that we are creating.

Getting Started

Head over to the Arrow online docs and the AppU Arrow videos. This should help you in setting up an Arrow project, installing the Salesforce connector and creating a basic model for the salesforce account object. Also, review the previous post which will be the starting point for this tutorial.

My Account model, Account.js is shown below:


var Arrow = require("arrow");

var Model = Arrow.Model.reduce("appc.salesforce/Account","Account",{
  "fields": {
    "Name": {
      "type": "string",
      "description": "Account Name",
      "readonly": false,
      "maxlength": 255,
      "required": true,
      "optional": false,
      "writeonly": false
    },
    "Type": {
      "type": "string",
      "description": "Account Type",
      "readonly": false,
      "maxlength": 40,
      "required": false,
      "optional": true,
      "writeonly": false
    },
    "BillingStreet": {
      "type": "string",
      "description": "Billing Street",
      "readonly": false,
      "maxlength": 255,
      "required": false,
      "optional": true,
      "writeonly": false
    },
    "Phone": {
      "type": "string",
      "description": "Account Phone",
      "readonly": false,
      "maxlength": 40,
      "required": false,
      "optional": true,
      "writeonly": false
    },
    "Website": {
      "type": "string",
      "description": "Website",
      "readonly": false,
      "maxlength": 255,
      "required": false,
      "optional": true,
      "writeonly": false
    },
    "lat": {
      "type": "String",
      "custom": true
    },
    "lon": {
      "type": "String",
      "custom": true
    }
  },
  "after": "addgps",
  "actions": [
    "create",
    "read",
    "update",
    "delete",
    "deleteAll"
  ],
  "singular": "Account",
  "plural": "Accounts"
});


module.exports = Model;

This model is basically a reduced Salesforce Account model that is exposed automatically in Arrow using the Arrow Salesforce connector with the addition of the lat/lon custom fields and a post block addgps. This was all described in the prior blog post.

So, now that we have geocode data with each account, we can make a call to Foursquare using the lat/lon and retrieve nearby coffee shops.

Modify the Account Model

In your favorite editor, open the model file, Account.js, and add a custom fields to the fields list:


"coffeeshops": {
  "type": "Array",
  "custom": true
}

Notice that the coffeeshops field is an array because we will fetch a number of coffeeshops near each account.

Adding the custom field above can be accomplished other ways as well. You could have added those custom fields inside the Arrow Admin Build screen while you were creating the original Account model (reduced from the base Salesforce Account Model exposed by the Arrow Salesforce connector). Or, you could create a new model that extends an existing Account model that you would have created inside the Arrow Admin Build screen.

Create a Post Block

In the blocks folder of the Arrow project, create a new js file. Mine is called addcoffeeshops.js and is shown below. Note that for more extensive, general purpose blocks you can use the “appc generate” command in a terminal (or command line) to create the block.


var Arrow = require('arrow');
var request = require('request');

var FSclient_id = "";
var FSclient_secret = "";
var baseURL = "https://api.foursquare.com/v2/venues/search?client_id="+FSclient_id+"&client_secret="+FSclient_secret+"&v=20141024&query=coffee&limit=3&ll=";

var PostBlock = Arrow.Block.extend({
  name: 'addcoffeeshops',
  description: 'add coffee shops to the retrieved data',

  action: function(req, resp, next) {
    // req.log.info("Post Example Block executed");

    var body = JSON.parse(resp.body);
    var data = body[body.key];
    var dataLen = data.length;
    var replies = 0;

    if(dataLen){
      data.forEach(function (_row, _index) {

        var url = baseURL+_row.lat+","+_row.lon;

        request(url, function (error, response, body) {
          if (!error && response.statusCode == 200) {
            var res = JSON.parse(body);

            if(res.response.venues.length>0) {
              var shops=[];
              for(var i=0;i0) {
            // _row.coffeeshops = response.response.venues; //assign all venue data

            var shops=[];
            for(var i=0;i

In the code above, for each Account, a REST web service call is made to the Foursquare API, using the request npm, with the code starting at:


request(url, function (error, response, body) {

In the reply of the call to the Foursquare API, the coffe shops are assigned to the model field array coffeeshops with the following code:


var res = JSON.parse(body);
if(res.response.venues.length>0) {
	var shops=[];
	for(var i=0;i

Since the calls to the Foursquare API are asynchronous, you need to keep track of the number of calls being made and when the final response is received. This is achieved with the following code:


replies++;
if(replies == dataLen) {
	setReply();
}

Set Post Block in Model

In the Account model, we need to add this block to the after property. However, since this is the second block to be executed, we will specify the blocks as an array as follows:


"after": ["addgps","addcoffeeshops"],

This will instruct Arrow to execute the addspgs post block after retrieving the data from Salesforce and then execute the addcoffeeshops post block.

Now the data returned to the mobile device looks like this:


{
  "success": true,
  "request-id": "ad3b22cd-aecf-4a72-bb80-248391f9c420",
  "key": "accounts",
  "accounts": [
    {
      "id": "001i000000PscewAAB",
      "Name": "GenePoint",
      "Type": "Customer - Channel",
      "BillingStreet": "345 Shoreline Park\nMountain View, CA 94043\nUSA",
      "Phone": "(650) 867-3450",
      "Website": "www.genepoint.com",
      "lat": 37.423958,
      "lon": -122.0721391,
      "coffeeshops": [
        {
          "id": "531f4262498e7dfd38788daf",
          "name": "Root Coffee Bar",
          "location": {
            "address": "1200 Charleston Rd",
            "lat": 37.42125,
            "lng": -122.071451,
            "distance": 307,
            "postalCode": "94043",
            "cc": "US",
            "city": "Mountain View",
            "state": "CA",
            "country": "United States",
            "formattedAddress": [
              "1200 Charleston Rd",
              "Mountain View, CA 94043",
              "United States"
            ]
          }
        },
        {
          "id": "5281225911d2fbe8d10f9463",
          "name": "Barefoot Coffee Roasters van",
          "location": {
            "lat": 37.419684936426464,
            "lng": -122.07105266770425,
            "distance": 485,
            "cc": "US",
            "city": "San Jose",
            "state": "CA",
            "country": "United States",
            "formattedAddress": [
              "San Jose, CA",
              "United States"
            ]
          }
        },
        {
          "id": "50660dc7e4b0b68b5dbe8858",
          "name": "Googleplex - Sight Glass Coffee",
          "location": {
            "address": "Google",
            "lat": 37.420315759073134,
            "lng": -122.07286151728987,
            "distance": 410,
            "postalCode": "94043",
            "cc": "US",
            "city": "Mountain View",
            "state": "CA",
            "country": "United States",
            "formattedAddress": [
              "Google",
              "Mountain View, CA 94043",
              "United States"
            ]
          }
        }
      ]
    },


…….


    {
      "id": "001i000000Pscf6AAB",
      "Name": "United Oil & Gas Corp.",
      "Type": "Customer - Direct",
      "BillingStreet": "1301 Avenue of the Americas \nNew York, NY 10019\nUSA",
      "Phone": "(212) 842-5500",
      "Website": "http://www.uos.com",
      "lat": 40.7616971,
      "lon": -73.9801263,
      "coffeeshops": [
        {
          "id": "4b6ad59ef964a5209be22be3",
          "name": "Coffee Cart",
          "location": {
            "address": "51st Street",
            "crossStreet": "7th Ave",
            "lat": 40.76337735085997,
            "lng": -73.98092822202503,
            "distance": 198,
            "cc": "US",
            "city": "New York",
            "state": "NY",
            "country": "United States",
            "formattedAddress": [
              "51st Street (7th Ave)",
              "New York, NY",
              "United States"
            ]
          }
        },
        {
          "id": "4ec11fdff5b93923c212cdc0",
          "name": "Coffee Cart",
          "location": {
            "address": "50th And 6th",
            "lat": 40.75999512452107,
            "lng": -73.98103726694443,
            "distance": 204,
            "postalCode": "11220",
            "cc": "US",
            "city": "New York",
            "state": "NY",
            "country": "United States",
            "formattedAddress": [
              "50th And 6th",
              "New York, NY 11220",
              "United States"
            ]
          }
        },
        {
          "id": "4ddc6032b0fba481fc81546f",
          "name": "Coffee Cart (46th & 6th)",
          "location": {
            "address": "46th St",
            "crossStreet": "at 6th Ave (NE Corner)",
            "lat": 40.75970808566679,
            "lng": -73.9874267578125,
            "distance": 654,
            "postalCode": "10036",
            "cc": "US",
            "city": "New York",
            "state": "NY",
            "country": "United States",
            "formattedAddress": [
              "46th St (at 6th Ave (NE Corner))",
              "New York, NY 10036",
              "United States"
            ]
          }
        }
      ]
    },
    {
      "id": "001i000000Pscf7AAB",
      "Name": "sForce",
      "BillingStreet": "The Landmark @ One Market\r\nSan Francisco\r\nCA\r\n94087\r\nUSA",
      "Phone": "(415) 901-7000",
      "Website": "www.sforce.com",
      "lat": 37.79396,
      "lon": -122.39496,
      "coffeeshops": [
        {
          "id": "4b0d71eaf964a5207b4823e3",
          "name": "The Coffee Bean & Tea Leaf",
          "location": {
            "address": "150 Drumm St",
            "crossStreet": "at Four Embarcadero Center",
            "lat": 37.79469538242046,
            "lng": -122.39654863295293,
            "distance": 161,
            "postalCode": "94111",
            "cc": "US",
            "city": "San Francisco",
            "state": "CA",
            "country": "United States",
            "formattedAddress": [
              "150 Drumm St (at Four Embarcadero Center)",
              "San Francisco, CA 94111",
              "United States"
            ]
          }
        },
        {
          "id": "4aafc57df964a520ab6420e3",
          "name": "Peet's Coffee & Tea",
          "location": {
            "address": "1 California St",
            "crossStreet": "at Drumm St",
            "lat": 37.793323943617715,
            "lng": -122.39672565009258,
            "distance": 170,
            "postalCode": "94111",
            "cc": "US",
            "city": "San Francisco",
            "state": "CA",
            "country": "United States",
            "formattedAddress": [
              "1 California St (at Drumm St)",
              "San Francisco, CA 94111",
              "United States"
            ]
          }
        },
        {
          "id": "4cc6f529be40a35dc8198d4c",
          "name": "Justin Herman Plaza- Keurig Coffee Pop Up",
          "location": {
            "lat": 37.79467,
            "lng": -122.394862,
            "distance": 79,
            "postalCode": "94105",
            "cc": "US",
            "city": "San Francisco",
            "state": "CA",
            "country": "United States",
            "formattedAddress": [
              "San Francisco, CA 94105",
              "United States"
            ]
          }
        }
      ]
    }
  ]
}

Summary

In this tutorial we saw how easy Arrow makes it to enhance an API using Blocks. We took a Salesforce Account model which had geocode data added to it (in the last blog post) and added a field for an array of related objects (coffee shops) and used the Post Block feature of Arrow to retrieve the data from the Foursquare API. Now the Account model returns the original account data and nearby coffee shops for each account so that the user can suggest a nearby meeting location for a client visit.

Account.js, addgps.js and addcoffeeshops.js for this sample project can be found here.

Read more about Arrow in the docs here.

1 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 1 Email -- 1 Flares ×

Sign up for updates!

Become a mobile leader. Take the first step to scale mobile innovation throughout your enterprise.
Get in touch
computer and tablet showing Appcelerator software
Start free, grow from there.
1 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 1 Email -- 1 Flares ×