booky99 booky99 - 2 months ago 16
Node.js Question

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.

Answer

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)
}
Comments