Hermann is correct, the urlopen,open function does not have a promise, but you can use the util module's promisify function to make one! Here's an example I did a few years ago
const util = require('util');
const urlopen = require('urlopen');
const urlopen1Options = { target: 'local:///helloworld1.json' }; // file present, will return a 200
const urlopen2Options = { target: 'local:///filenotthere.json' }; // not found, will return a 404
const urlopen3Options = { target: 'local:///helloworld3.json' }; // file present, will return a 200
const request = util.promisify(urlopen.open);
const requestArray = [request(urlopen1Options), request(urlopen2Options), request(urlopen3Options)];
async function callReadFiles() {
try {
// returns urlopen response or error objects for each request in the array
// wait for all of the urlopen.open async functions to complete.
// You can also add a .catch((err) => errorHandlingFunction(err))
await Promise.all(requestArray).then((values) => aggregateResponses(values));
console.notice('completed callReadFiles asynchronous function');
} catch(exception) {
console.error('callReadFiles exception: %j', exception);
}
};
async function aggregateResponses(responseArray) {
try {
let promiseArray = [];
// define a promise for the response.readAsJSON function
const readAsJSONPromise = (response) => {
return new Promise((resolve, reject) => {
response.readAsJSON (function (readAsJSONError, jsonData) {
if (readAsJSONError) {
reject(readAsJSONError);
} else {
resolve(jsonData);
}
});
});
};
// ensure each urlopen response provided a HTTP 200. Non 200's may not have a JSON response
// which would cause readAsJSON to throw an exception. This is just an example, but other
// error handling may be more appropriate, ie, don't build the promiseArray at all but throw
// an exception via the apim.error function.
for (var i = 0; i < responseArray.length; i++) {
if (responseArray[i].statusCode === 200) {
promiseArray.push(readAsJSONPromise(responseArray[i]));
} else {
// handle error here if you wish
}
}
// wait for all of the readAsJSON async functions to complete.
// You can also add a .catch((err) => errorHandlingFunction(err))
await Promise.all(promiseArray).then((values) => aggregateResults(values));
console.info('completed aggregateResponses asynchronous function');
} catch(exception) {
console.error('aggregateResponses exception: %j', exception);
}
}
function aggregateResults(jsonArray) {
try {
// aggregate the data in the array of responses per requirements
let result = {aggregate: jsonArray};
// output the aggregated result
session.output.write(result);
apim.output('application/json');
console.info('completed aggregateResults function');
} catch(exception) {
console.error('aggregateResults exception: %j', exception);
}
}
callReadFiles();
console.info('mainline event queue completes here. This will log before any of the asynchronous functions execute.')
This will build a promise array for urlopen.open with the options for each. The mainline will then simply call the callReadFiles functions and the mainline event queue is complete. The callReadFiles function will await for all of those promises to complete before calling the aggregateResponses function which will receive an array containing each urlopen's response object. This function will build a promise array for each response's response.readAsJSON in my case (you could use readAsBuffer|XML of course), however, I do check each response's statuscode and only do the readAsJSON promise for those responses that received a HTTP 200 response. When all of the readAsJSON promises have been completed, an array of JSON results are provided to the aggregateResults function. I don't do a lot there, but that is where you would do whatever you want to do after all of the readAsJSON async functions are completed. You'll have an array of response bodies for which you can use to do whatever you wish or perhaps you could ignore the response bodies and do something totally different. The key is the execution of the JavaScript is happening after all of the readAsXXXX functions have completed.
Best Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
------------------------------
Original Message:
Sent: Tue March 07, 2023 02:42 AM
From: Hermann Stamm-Wilbrandt
Subject: Gateway Script URL Open inside for each works in async mode and doesnt wait for response
I am not sure whether you can directly wait for a urlopen, as it has no Promise.
Create an async function with urlopen inside "new Promise" as I did in wait.js.
Then you can await a call for that function like I did:
https://stamm-wilbrandt.de/en/blog/sync_wait.js%20and%20wait.xsl.html
------------------------------
Hermann Stamm-Wilbrandt
Compiler Level 3 support & Fixpack team lead
IBM DataPower Gateways (⬚ᵈᵃᵗᵃ / ⣏⠆⡮⡆⢹⠁⡮⡆⡯⠂⢎⠆⡧⡇⣟⡃⡿⡃)
https://stamm-wilbrandt.de/en/blog/
Original Message:
Sent: Mon March 06, 2023 06:17 PM
From: Kshitij Khanna
Subject: Gateway Script URL Open inside for each works in async mode and doesnt wait for response
For a certain requirement, I need to call the same backend with different dynamic values, the values are available in an input JSON structure, so say if I have 10 values then I run a for loop on the 10 values and then run the url open call inside the loop based on certain conditions but unfortunately the code works asynchronously and I dont get the returned value in time to be passed to the next url open call.
I tried the Async Await and promise methods but the function hasnt helped, I have tried running the code directly and also by placing the code in an if condition.
Can you please let me know how to use the url open Gateway script function to ensure that it waits for the response so I can use its response to call the next url open and use the final response in my code.
------------------------------
Kshitij Khanna
------------------------------