I have a pretty simple scenario, with a RESTful endpoint in Node / Express.js that needs to invoke another REST service and return its result.
The trouble I'm facing is getting the response in the Express method to send the appropriate data back.
var express = require('express');
var app = express();
app.post('/test', function(req, res) {
async.series([ function(callback) {
var httpConfig = app.config.evaluateRuleService;
logger.info("About to make request");
// make an async call here
require('../utils/http-wrapper/http').post(req.body, httpConfig,
function(err, data) {
logger.info("still have res: " + res);
logger.info("Got response: " + data);
// data.isAuthorized is set by the service being invoked
callback(false, data);
});
} ],
function(err, results) {
logger.info("Inside collate method");
// correctly gets invoked after async call completes
// but res.json isn't sending anything to the client
res.json({
authorized : results.isAuthorized
});
})
// Problem: The client is receiving the response before the async call completes
});
Here's the log output:
"Listening on port 8897","time":"2015-03-27T19:22:24.435Z","v":0}
"About to make request","time":"2015-03-27T19:22:30.608Z","v":0}
fetch() POST http://localhost:8897/test
**<logs of the server method being invoked are printed out>**
"still have res: [object Object]","time":"2015-03-27T19:22:30.616Z","v":0}
"Got response: {\"isAuthorized\":true}","time":"2015-03-27T19:22:30.616Z","v":0}
"Inside collate method","time":"2015-03-27T19:22:30.617Z","v":0}
So the order occurs in an agreeable way, however, the clients invoking this endpoint are seeing an empty result being returned, and not the expected authorized : results.isAuthorized which I'm trying to send to the response in the last callback.
Much thanks
Edit with solution:
As Peter and Kevin point out, there were two issues going on, and it was a misdiagnosis to think the response was sending too early.
The results object is indeed an array, and my relevant index is [0]. Then I needed to convert the String response as a JSON object to be able to access the fields I need.
The answer in the callback function that solves this is:
function(err, results) {
logger.info('Inside collate method');
// Need to access array at appropriate index
logger.info('Authorize Response: ' + results[0]);
// Need to parse the value at index 0 as a JSON object
var authorizeResponse = JSON.parse(results[0]);
res.json({
authorized : authorizeResponse.isAuthorized
});
}
You don't have the correct signature for async.series. The arguments to the final callback are error, arrayOfResults, so you need results[0].isAuthorized to get the correct value. My theory is your code generates the object {isAuthorized: undefined} because the array of results has no isAuthorized property. This then serializes to an empty object in JSON as shown below:
> JSON.stringify({isAuthorized: undefined})
'{}'
The timing and control flow are otherwise OK though. The problem is not the response being sent too early.