Can you recommend a way to handle this or if using waitForComplete is ok in this scenario? We are using Apigee Hybrid 1.5.3 version
Do not use waitForComplete. It is an anti-pattern in Apigee. ps: if you find any examples that continue to show this, please flag them for me.
The correct approach is to use a callback for the httpClient.send method. I think this is documented. Simple example:
var prefix = 'jsvariable';
function cb(response, error) {
if (response) {
context.setVariable(prefix +'.response-status', response.status);
}
else {
context.setVariable(prefix +'.error', 'Whoops: ' + error);
}
}
var url = properties.targetBase + '/segment?q1=0.2&q2=whatever';
var headers = { 'ID-Index' : id, 'Other-Header' : 'other-value' };
var req = new Request(url, 'GET', headers);
httpClient.send(req, cb);
That sends a single http request, and handles the response in a callback.
Now, suppose you want to send multiple HTTP requests, and the number of HTTP requests is not known until runtime. In that case you need to invoke all of the calls, each possibly with their own callback. You can do that with JS closures.
Let’s say you have an array of data items, of indeterminate length, and you want to make a set of outbound calls that execute in parallel, one for each item in the array. To do that, you could do something like this:
var start = Date.now();
function indexedOnComplete(id, numberOfCalls, response, error) {
var prefix = 'jscall.'+ id.toFixed(0);
context.setVariable(prefix +'.completed-at', String(Date.now() - start));
if (response) {
context.setVariable(prefix +'.response-status', response.status);
}
else {
context.setVariable(prefix +'.error', 'Whoops: ' + error);
}
if (numberOfCalls - 1 == id) {
context.setVariable('jscall.all-done', String(Date.now() - start));
}
}
function invokeOne(id, dataItem, cb) {
var url = properties.target + '/pathsegment?item=' + dataItem ;
var headers = { 'ID-Index' : id };
var req = new Request(url, 'GET', headers);
httpClient.send(req, cb);
}
// ====================================================================
// get data items from... somewhere
const dataItems = [ ???, ???, ... ] ;
var numberOfCalls = dataItems.length;
context.setVariable('number-of-calls', numberOfCalls.toFixed(0));
dataItems.forEach(function(current, index) {
context.setVariable('jscall.' + index.toFixed(0) + '.dataItem', current.toFixed(2));
var cb = function(response, error) {
return indexedOnComplete(index, numberOfCalls, response, error);
};
return invokeOne(index, current, cb);
});
The JS will finish after all the calls finish.
If you have long running HTTP calls, you may need to set the timeLimit attribute on the JavaScript policy XML to accommodate that:
<Javascript name='JS-Invoke-Calls' timeLimit='22000' >
<Properties>
<Property name='target'>https://my-target.com</Property>
</Properties>
<ResourceURL>jsc://invoke-calls-in-parallel.js</ResourceURL>
</Javascript>