Search code examples
javascriptscopehttp-getnode-rest-client

How can I obtain API response data from within a function?


Javascript noob here. Apologies if there are a ton of duplicate questions out there because it seems like this must be a fundamental js function thing, but I honestly can't find an answer to this. I'm trying to wrap an API GET call in a function, and I'm running into behavior that I don't understand. The code in question:

I'm using the node-rest-client package to call the mapquest geocoding API. I'm interested in the lat/long data only.
var Client = require('node-rest-client').Client;

If I make the GET call like this, I can access parsed as an object, which is what I want.

var address = 'New York'
var client = new Client();
var parsed;
client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
                'key=' + mapquestKeys.consumer_key +
                '&location=' + address,
            function(data, response) {
              parsed = data.results[0].locations[0].latLng
              }
            );

// parsed == {lat, long}

But if I wrap this in a function:

function geocode(address){
  var client = new Client();
  var parsed;
  client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
                  'key=' + mapquestKeys.consumer_key +
                  '&location=' + address,
              function(data, response) {
                parsed = data.results[0].locations[0].latLng
                }
              );
    return parsed
}

var address = 'New York'
parsed = geocode(address);

// parsed === undefined

parsed doesn't seem to be affected by the inner function; it's undefined. How can I return parsed as an object containing the data I want as in the first example? What the heck is going on here?


Solution

  • In:

    function geocode(address){
      var client = new Client();
      var parsed;
      client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
                      'key=' + mapquestKeys.consumer_key +
                      '&location=' + address,
                  function(data, response) {
                    parsed = data.results[0].locations[0].latLng
                    }
                  );
        return parsed
    }
    
    var address = 'New York'
    parsed = geocode(address);
    
    // parsed === undefined
    

    You never defined parsed outside of the scope of your function. Also you're returning parsed inside of the function before it's had a chance to retrieve from the GET request. If you wanted to do it this way, you'd need to put return(prased) inside the callback function of client.get. A better way to do it is to wrap it inside a Promise like so:

    function geocode(address){
        return new Promise((resolve, reject) => {
            var client = new Client();
            client.get("http://www.mapquestapi.com/geocoding/v1/address?" +
                    'key=' + mapquestKeys.consumer_key +
                    '&location=' + address,
                    function(data, response) {
                    if(data){
                        resolve(data.results[0].locations[0].latLng)
                    }
                    else{
                        reject(response)
                    }
                      });
        })
      };
    
    
    var address = 'New York';
    var parsed;
    geocode(address).then(function(latlong){
        parsed = latlong
    }).catch(err => {
        console.log(err)});
    

    Here, parsed will only evaluate to latlong once the Promise has been resolved (the GET request has returned successful). It will also reject the Promise if data of the GET request is NULL and return an error.

    If you wanted to then do something with parsed you could include that in the .then() statement.

    Learning how to code in Javascript means learning how to write code asynchronously. Promises help you treat things which are by default asynchronous as synchronous.