booky99
booky99

Reputation: 1456

AWS return callback within a callback

I'm wanting to return a value in the main of my AWS function. I'm having trouble getting the data to pass from the first callback so I can send it to the final one.

  /** module used for outbound http requests */
    var request = require('request');

    /** module used for parsing XML easily. https://www.npmjs.com/package/xml2js*/
    var parseString = require('xml2js').parseString;
exports.handler = (event, context, callback) => {

    // testing array of coordinates
    var arrayOfPoints = [39.7683800, -86.1580400, 41.881832, -87.623177];
    var results = getXMLFromNOAA(arrayOfPoints);
    callback(null, results); // <- returns 'undefined' in the AWS console. I'm assuming race condition.
};

/**
* getXMLFromNOAA
*
* This is a function used for figuring out the functionality of NOAA XML parsing
*
* @param arrayOfPoints {Array[Double]} - An evenly numbered index array of latitudes and longitudes
*
* @return result {XML/JSON} - weather information abled to be parsed
*/
function getXMLFromNOAA(arrayOfPoints, callback) {

    var baseURL = "http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdXMLclient.php?whichClient=NDFDgenLatLonList&lat=&lon=&listLatLon=";

    // for-loop getting all points and dynamically adding them to the query url string
    // iterate 2 at a time since they are coupled coordinates (e.g. [lat1, lng1, lat2, lng2, ... latN, lngN])
    for(var i = 0; i < arrayOfPoints.length; i = i + 2)
    {
        // if we're at the end of the arrayOfPoints, finish up the chain of query coordinates
        if( (i+2) == arrayOfPoints.length)
        {
            baseURL = baseURL.concat(arrayOfPoints[i]);
            baseURL = baseURL.concat("%2C");
            baseURL = baseURL.concat(arrayOfPoints[i+1]);
        } 
        else 
        {
            baseURL = baseURL.concat(arrayOfPoints[i]);
            baseURL = baseURL.concat("%2C");
            baseURL = baseURL.concat(arrayOfPoints[i+1]);
            baseURL = baseURL.concat("+");
        }
    }

    // TIME
    baseURL = baseURL.concat("&lat1=&lon1=&lat2=&lon2=&resolutionSub=&listLat1=&listLon1=&listLat2=&listLon2=&resolutionList=&endPoint1Lat=&endPoint1Lon=&endPoint2Lat=&endPoint2Lon=&listEndPoint1Lat=&listEndPoint1Lon=&listEndPoint2Lat=&listEndPoint2Lon=&zipCodeList=&listZipCodeList=&centerPointLat=&centerPointLon=&distanceLat=&distanceLon=&resolutionSquare=&listCenterPointLat=&listCenterPointLon=&listDistanceLat=&listDistanceLon=&listResolutionSquare=&citiesLevel=&listCitiesLevel=&sector=&gmlListLatLon=&featureType=&requestedTime=&startTime=&endTime=&compType=&propertyName=&product=time-series&begin=2016-09-04T00:00:00&end=2016-09-11T00:00:00");

    // CHARACTERISTICS REQUESTED
    // http://graphical.weather.gov/xml/docs/elementInputNames.php
    baseURL = baseURL.concat("&Unit=e&maxt=maxt&mint=mint&temp=temp&appt=appt&rh=rh&sky=sky&wwa=wwa&iceaccum=iceaccum&ptornado=ptornado&phail=phail&ptstmwinds=ptstmwinds&pxtornado=pxtornado&pxhail=pxhail&ptotsvrtstm=ptotsvrtstm&wgust=wgust");

    // Used for testing and seeing the final result
    console.log(baseURL);

    request(baseURL, function (error, response, body) 
    {
        if (!error && response.statusCode == 200) 
        {
            parseString(body, function (err, result) {
                console.log('inside parseString: ' + result); // <- this prints but it won't show up in the main
                // callback(null, result); <- doesnt work
                return result; // doesnt work either
            });
        }
    })
}

I want to be able to make my code more modular for scalability. I know theres a way to take the async process of the getXMlFromNOAA and perform them iteratively. I'm just not as familiar with JavaScript as I should be. Any help would really be appreciated.

Upvotes: 0

Views: 84

Answers (2)

Jason Livesay
Jason Livesay

Reputation: 6377

Thats not how callbacks work. Change the handler to something like this:

exports.handler = (event, context, callback) => {
  var arrayOfPoints = [39.7683800, -86.1580400, 41.881832, -87.623177];
  getXMLFromNOAA(arrayOfPoints, function(result) {
    console.log('returned');
    console.log(result);
    callback(null, result);
  });
};

Also uncomment (go back) to the callback(result) in getXMLFromNOAA;

Also for NOAA there is a module. Always search node-modules/npmjs.com/npms.io first before reinventing the wheel. The example here https://github.com/thataustin/noaa-forecasts is very similar to what you are doing so I would start with that.

If you want to simplify async stuff in the future you can use babel with async and await keywords. But you will need to make sure you really learn callbacks and promises first.

Upvotes: 0

abdulbari
abdulbari

Reputation: 6232

You can use async module to make it more readable and flexible and also free from the asynchronous issue. Write your stuff something like this

/** module used for outbound http requests */
var request = require('request');
var async = require('async');

/** module used for parsing XML easily. https://www.npmjs.com/package/xml2js*/
var parseString = require('xml2js').parseString;
exports.handler = (event, context, callback) => {

    async.waterfall([

        function(next) {
            // testing array of coordinates
            var arrayOfPoints = [39.7683800, -86.1580400, 41.881832, -87.623177];
            var results = getXMLFromNOAA(arrayOfPoints, next);

        },
        function(baseURL, next) {

            request(baseURL, function(error, response, body) {
                if (!error && response.statusCode == 200) {
                    parseString(body, function(err, result) {
                        console.log('inside parseString: ' + result); // <- this prints but it won't show up in the main
                        if (!err)
                            next(null, result);
                    });
                }
            })

        }
    ], function(err, result) {
        if (!err) {
            callback(null, results); // <- returns 'undefined' in the AWS console. I'm assuming race condition.
        }

    })

};

/**
 * getXMLFromNOAA
 *
 * This is a function used for figuring out the functionality of NOAA XML parsing
 *
 * @param arrayOfPoints {Array[Double]} - An evenly numbered index array of latitudes and longitudes
 *
 * @return result {XML/JSON} - weather information abled to be parsed
 */
function getXMLFromNOAA(arrayOfPoints, next) {

    var baseURL = "http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdXMLclient.php?whichClient=NDFDgenLatLonList&lat=&lon=&listLatLon=";

    // for-loop getting all points and dynamically adding them to the query url string
    // iterate 2 at a time since they are coupled coordinates (e.g. [lat1, lng1, lat2, lng2, ... latN, lngN])
    for (var i = 0; i < arrayOfPoints.length; i = i + 2) {
        // if we're at the end of the arrayOfPoints, finish up the chain of query coordinates
        if ((i + 2) == arrayOfPoints.length) {
            baseURL = baseURL.concat(arrayOfPoints[i]);
            baseURL = baseURL.concat("%2C");
            baseURL = baseURL.concat(arrayOfPoints[i + 1]);
        } else {
            baseURL = baseURL.concat(arrayOfPoints[i]);
            baseURL = baseURL.concat("%2C");
            baseURL = baseURL.concat(arrayOfPoints[i + 1]);
            baseURL = baseURL.concat("+");
        }
    }

    // TIME
    baseURL = baseURL.concat("&lat1=&lon1=&lat2=&lon2=&resolutionSub=&listLat1=&listLon1=&listLat2=&listLon2=&resolutionList=&endPoint1Lat=&endPoint1Lon=&endPoint2Lat=&endPoint2Lon=&listEndPoint1Lat=&listEndPoint1Lon=&listEndPoint2Lat=&listEndPoint2Lon=&zipCodeList=&listZipCodeList=&centerPointLat=&centerPointLon=&distanceLat=&distanceLon=&resolutionSquare=&listCenterPointLat=&listCenterPointLon=&listDistanceLat=&listDistanceLon=&listResolutionSquare=&citiesLevel=&listCitiesLevel=&sector=&gmlListLatLon=&featureType=&requestedTime=&startTime=&endTime=&compType=&propertyName=&product=time-series&begin=2016-09-04T00:00:00&end=2016-09-11T00:00:00");

    // CHARACTERISTICS REQUESTED
    // http://graphical.weather.gov/xml/docs/elementInputNames.php
    baseURL = baseURL.concat("&Unit=e&maxt=maxt&mint=mint&temp=temp&appt=appt&rh=rh&sky=sky&wwa=wwa&iceaccum=iceaccum&ptornado=ptornado&phail=phail&ptstmwinds=ptstmwinds&pxtornado=pxtornado&pxhail=pxhail&ptotsvrtstm=ptotsvrtstm&wgust=wgust");

    // Used for testing and seeing the final result
    console.log(baseURL);
    //retun to callback after getting URL
    next(null, baseURL)
}

Upvotes: 2

Related Questions