You're right it does have something to do with asynchrony. The problem is that the API call does not block so you return immediately without reassigning the value. The simplest way to solve this would be to use a callback i.e.
/* GET funnel page. */
router.get('/funnel', function(req, res, next) {
var score = 'test2';
GetQuery('Bars', function(err, score) {
res.render('funnel', {title : score});
});
});
function GetQuery(query, cb) {
factual.get('/t/places-us', {q:query,limit: 1, filters:{"$and":[{"region":{"$eq":"NY"}},{"locality":"pittsford"}]}}, function (error, res) {
cb(error, res.data[0].email);
});
}
Another option would be to use a Promise or something like RxJS. Which would both let you use a more fluent style for your code:
Promise:
/* GET funnel page. */
router.get('/funnel', function(req, res, next) {
var score = 'test2';
GetQuery('Bars').then(function(score) {
res.render('funnel', {title : score});
});
});
var getQuery = Promise.denodify(factual.get);
function GetQuery(query) {
return getQuery('/t/places-us', /*Query parameters*/).then(function (res) {
return res.data[0].email;
});
}
RxJS
/* GET funnel page. */
router.get('/funnel', function(req, res, next) {
var score = 'test2';
GetQuery('Bars').subscribe(function(score) {
res.render('funnel', {title : score});
});
});
var getQuery = Rx.Observable.fromNodeCallback(factual.get, null,
function(res) {
return res.data[0].email;
});
function GetQuery(query) {
return getQuery('/t/places-us', /*Query*/);
}
factual.get()looks like it's an asynchronous function. That means that it returns its value by calling the callback sometime LATER. ThusGetQuery()has already returned before the value oftesthas even been set. As such, you cannot return the value fromGetQuery(). You must return the result in an async-compatible manner which means using a promise or a callback.