I'm playing with retool and trying to fetch some data through API call to Asana. I'm making the call to the API endpoint and getting some results (tasks from a Asana project) in a table. Now One of the columns is an user ID (for example the ID of task assignee). I want to make a second API call for each table row to fetch the Name of this User (by sending the user ID over the 2nd API call).
So what is the right mechanism to achieve this with retool?
You can write a js query to loop through the results from the first API call
for(i=0;i<query1.value.length; i++){
query2.trigger({
additionalScope: {
userID: query1.value[i].userID
},
onSuccess: function(data) {
console.log('Successully ran!'); // you don't really need this as it's more for testing...
},
onFailure: function(error){
console.log("Something broke");
},
})
}
Then your your second API call would trigger in the above loop
query2 (or api call) would take that param userID
select from yourasanatable(userName) where userID = ({{userID}}
Thanks, this works and actually I'm able to get the data from the 2nd API call, but it doesn't show in a table, maybe because i'm getting single record on every iteration. Any idea how to append row to table on each response I get from the 2nd API call with data?
If you’re getting the name from the second api call you could use temp state to store the first query and then add to that state the result for each iteration and have the table be populated with that temp state value.
Or are you getting more than just the name from the second query?
As you can see the "assignee" column contains some JSON data.
Now, I want to make a 2nd API call to Asana (GET /users/{user_gid}), where I provide the "gid" number to Asana, and it returns an array with Name of the person and some other properties.
As a next step I would want to propagate the as_name column with the "name" coming from the 2nd API call, so that each row gets a corresponding value (Name of person) in the as_name column.
set the table to be populated with the value of a tempState var..
then for each call
for(i=0;i<query1.value.length; i++){
query2.trigger({
additionalScope: {
userID: query1.value[i].userID
},
onSuccess: function(data) {
tempState.setIn( [ i, "as_name" ], query2.value[i]) //this is where you assign the value in the temp variable
console.log('Successully ran!'); // you don't really need this as it's more for testing...
},
onFailure: function(error){
console.log("Something broke");
},
})
Your temp var could be created as a js transformer:
and formatted like the following
const objs = [
{
"gid": "",
"assignee": 2,
"as_name": 5 // this is where you append to the temp var from query 2
for (i=0; i<getAssigneeDetails.data.data.length; i++) {
getAssigneeDetails.trigger({
additionalScope: {
userID: getTasksInBoard.data.data[i].assignee.gid
},
onSuccess: function(data) {
state1.setIn( [0, "as_name"],getAssigneeDetails.data.data[i].name ); //not sure what the key of this result set is (name?)
//You will overwrite the state1 value of as_name for each loop through... so you can concatenate the state1 value after checking to see if it isn't blank so as to then always concatenate
if(state1.value['0'].as_name != "" {
state1.setValue(state1.value.concat(getAssigneeDetails.data.data[i].name))
}
console.log("Successully ran!", getAssigneeDetails.data.data[i]);
},
onFailure: function(error) {
console.log("Something broke");
},
})
}
for (i=0; i<5; i++) { //testing with just 5 iterations
getAssigneeDetails.trigger({
additionalScope: {
userID: getTasksInBoard.data.data[i].assignee.gid
},
onSuccess: function(data) {
state1.setValue(state1.value.concat(getAssigneeDetails.data.data.name)) //the API call always returns 1 result therefore no need to use [i] here
console.log("Successully ran!", i);
},
onFailure: function(error) {
console.log("Something broke");
},
})
}
Interesting that for every RUN of this JS it adds only 1 value to state1.value - isn't it supposed to run 5 times and add all 5? Very strange...
Any idea why in the log "i" is always 5 - e.g. getting always "Successfuly ran! 5"
Yep move the console.log call up right after the for statement and you should see output - the onSuccess: function(data) callback will output after everything is complete from what I can see
so if you move console.log... like here you should see correct output... for (i=0; i<getAssigneeDetails.data.data.length; i++) { console.log('Successully ran! ' + getAssigneeDetails.data.data[i]); .......
Can't say for sure why this works and not in the callback maybe someone else has a better understanding of this than I do...
It looks like you got this sorted out. Thanks Scott for your answers; really helpful! There's some trickiness involved here I believe due to JavaScripts asynchronous behavior. The rearranging of console.logs may work but keep in mind the variable "i" equates to 5 before the onSuccess functions are even called. That could be the reason 5 keeps appearing.