Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Whisking Functions With Promises

DZone's Guide to

Whisking Functions With Promises

Read on to see how one developer integrated the Google Maps API into his first ever Node.js-based project and made it work with Apache OpenWhisk.

· Integration Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

Over the past few weeks, I have been learning and enhancing my skills around the new buzz word "serverless" and trying to understand what this buzz is all about. As an ardent open-source developer, I was looking for a platform where I can develop and deploy the serverless functions, which is when I stumbled upon Apache OpenWhisk.

In this post, I will demonstrate how to build a simple Node.js function that can do reverse geocoding using the Google Maps API, and how to deploy the functions on to Apache OpenWhisk.

The context is to show the building of an Apache OpenWhisk JavaScript action, which involves a callback. As most of us are familiar with the Google Maps API (which has lots of callbacks), it provides a good example for this blog.

The source code of this blog is available on my GitHub repository.

Since I am a newbie to Node.js development, I did make several mistakes around configuration, function, definition, and invoking the function. This post will explain what I did wrong, and what I did to make the function work as expected.

With the context set, let's start writing the function (or, the first wrong way I tried) that does the reverse geocoding for us using the Google Maps API:

'use strict';
const gmap = require('@google/maps');

function location(params) {
  const latlng = JSON.parse(JSON.stringify(params.coords))
  const gmapClient = gmap.createClient({
    key: process.env.GOOGLE_MAPS_API_KEY
  })
  gmapClient.reverseGeocode({
    "latlng": latlng,
    "result_type": "postal_code"
  },function(function(results, status){
   if (status === 'OK'){
     return {status: 'Err',location: response.json.results[0].formatted_address}
   }else{
      return {status: status,location: 'Unknown'}
   }
  })
  return {status: status,location: 'Unknown'}
}

global.main = location;

View the code on Gist.

For the sake of brevity and sticking to the context of this post, I am skipping the details of the source repo and related npm scripts. For the rest of this article, we only need to know:

  • build is npm run build 
  • action deploy is npm run deploy 
  • action invoke is npm run dev 

After we build, npm run build, and deploy, npm run deploy, the function, we invoke the action via npm run dev which returns the following result:

 {status: status,location: ‘Unknown‘} 

I did not have any clue as to why that did not work. 

However, with a bit of research and consulting the OpenWhisk actions document I found that I was not properly handling the callback function of the Google Map client "reverseGeocode" method. I then decided to wrap the callback within a Promise and return a Promise as a response to the OpenWhisk Node.js action.

Following the OpenWhisk actions documentation, I tried updating the code as:

'use strict';

const gmap = require('@google/maps');

function location(params) {

  const latlng = JSON.parse(JSON.stringify(params.coords))

  const gmapClient = gmap.createClient({
    key: process.env.GOOGLE_MAPS_API_KEY
  })

  return new Promise(function (resolve, reject) {
    gmapClient.reverseGeocode({
      "latlng": latlng,
      "result_type": "postal_code"
    }, function (results, status) {
      let respStatus = response.json.status
      if (respStatus === 'OK') {
        resolve({ status: respStatus, location: response.json.results[0].formatted_address })
      } else {
        reject({ status: respStatus, location: "" })
      }
    })
  });
}

global.main = location;

View the code on Gist.

Invoking the action post doing npm run build took me from bad to worse, with action hung and no response.

Polling the OpenWhisk logs via wsk activation poll showed the following lines:

Activation: 'location-finder' (750f66bd750d426d8f66bd750d026d2a)[
"2018-02-23T05:27:06.453Z stderr: There was an issue while collecting your logs. Data might be missing."
]

With further analysis and debugging, I found that I needed to make the Google Map client promise aware.

I made one further and final modification to the function:

'use strict';

const gmap = require('@google/maps');

function location(params) {

  const latlng = JSON.parse(JSON.stringify(params.coords))

  const gmapClient = gmap.createClient({
    key: process.env.GOOGLE_MAPS_API_KEY,
    Promise: Promise
  })

  return gmapClient.reverseGeocode({
    "latlng": latlng,
    "result_type": "postal_code"
  }).asPromise()
    .then((response) => {
      let status = response.json.status
      let location = ""
      if (status === 'OK') {
        location = response.json.results[0].formatted_address
      }
      return { status: status, location: location }
    }).catch((err) => {
      console.log("Err: ", err)
      return { status: err, location: "unknown" }
    })
}

global.main = location;

View the code on Gist.

Two important changes:

  • Line#11 - where I created the Google Maps client to promise aware.
  • I modified the node function to return the promise from the location function via the asPromise() method.

Doing a rebuild, deploy, and run returned the expected response:

{
"location": "New Row, London WC2N 4LH, UK",
"status": "OK"
}

In this example, we saw how Promise can be configured on the Google Map client. If you are using similar functions from the other API, you need to check on how to hook on to the API call that can give you a handle for a Promise.

In summary, the crucial learnings here are about how to return a Promise the correct way from an Apache OpenWhisk JavaScript action. When invoking the OpenWhisk action, it should return the response which will be part of the future (Promise), and should not exit the function immediately after the main function ends.

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
integration ,node.js ,google maps api ,apache openwhisk ,api integration

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}