How to use async/wait to allow multiple, synchronous, API calls in a Trigger or Action

  • 5 December 2022
  • 0 replies
  • 5095 views

Userlevel 1

I have seen several posts on the forum asking how to perform multiple http requests in the same action/trigger. Generally, these need to be run in order so that results from one can be used in the following request. Some of the answers were a bit complex, so here’s a simplified version that you can use to run requests synchronously.

const options1 = {
url: `https://${bundle.authData.client_domain}/api/rest/v2/grant_request/65}`,
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'Authorization': `Bearer ${bundle.authData.access_token}`
},
params: {
cols: '["amount_requested"]'

},
};
const options2 = {
url: `https://${bundle.authData.client_domain}/api/rest/v2/grant_request/1188}`,
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'Authorization': `Bearer ${bundle.authData.access_token}`
},
params: {
cols: '["amount_requested"]'
},
};


// We put all this in an async function so that we can use "await"
// in it, to make the API calls synchronous.
// Note: if there are some calls that can be done simultaneously
// (i.e. none of them rely on information from any of the others),
// then there's probably something that can be done using
// await Promise.all([fetchPromise1, fetchPromise2, fetchPromise3]);
// and not using await for those promises.

async function do_it() {
const result1 = await z.request(options1);
// you could use something from result1.json here to change
// some parameters in options2, for the second request
const result2 = await z.request(options2);
const r = {"r1":result1.json, "r2":result2.json};
return r;
}

return do_it();

Output:

{
"r1": {
"grant_request": {
"id": 65,
"amount_requested": 4000
}
},
"r2": {
"grant_request": {
"id": 1188,
"amount_requested": 10000
}
}
}

The key elements are:

  1. The overall code block has to return a Promise. The async function returns a promise, so you can return the output of that function.
  2. You can only use await inside a function that is marked as async.
  3. Therefore, you can put all of the logic inside an async function (“do_it”, above), and use “await z.request(options);” inside the function. The value returned from that function is the actual results object, NOT a Promise.
  4. There is no particular need to use .then() on the “await”ed requests. Any logic that would have gone in the .then() block can simply be done on the next lines.
  5. In my example above, I just grab two records over the API, so, technically, it would be better to run them simultaneously (asynchronously) instead of consecutively (synchronously). To do so, you could use the following do_it() function. We no longer await the results of each request: result1 and result2 are Promises, not data objects. “await Promise.all(array of Promises)” will only proceed once all the Promises are returned.
async function do_it() {
const result1 = z.request(options1).then((results)=>results.json);
const result2 = z.request(options2).then((results)=>results.json);
const s = await Promise.all([result1, result2]);
const r = {"results":s}
return r;
}

Output:

{
"results": [
{
"grant_request": {
"id": 65,
"amount_requested": 4000
}
},
{
"grant_request": {
"id": 1188,
"amount_requested": 10000
}
}
]
}

In this case, I did use .then() on the two requests, so that they would only return the data I wanted (.json), not the entire results object.

The order of the objects in the array returned from Promise.all is the same as the order of the items in the array in the arguments to the function.

For my purposes, being able to treat requests as synchronous functions makes my code a LOT simpler, especially when the logic needs to branch depending on the results of some of the requests. Without the ability to use “await”, the code would be a horrendous mess of nested .then() statements.

 

Hope that helps others.

Stephen


This post has been closed for comments. Please create a new post if you need help or have a question about this topic.