Second API call to fetch additional details and fill in a table

Hi All,

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?

Thank in advance.

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?

Hi,

I'm uploading a picture of the how the table looks like after the first API call to Asana which returns Tasks with additional details for each task.

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.

Suggestions how to achieve it will be helpful...

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:
Screen Shot 2022-03-14 at 9.30.57 AM

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

}.....//more can be added..
]

check this out
https://docs.retool.com/docs/temporary-state

Hi,

I'm working on this and something seems very weird and trying to debug it... so trying this simple js code:

for (i=0; i<5; i++) {
      
  getAssigneeDetails.trigger({
      additionalScope: {  
      userID: getTasksInBoard.data.data[i].assignee.gid
      },
        onSuccess: function(data) {
        state1.setIn( [i, "as_name"],getAssigneeDetails.data.data ); 
        console.log("Successully ran!", i); 
        },
       onFailure: function(error) {
         console.log("Something broke");
        },
      })
}

Interesting, that in the console log I'm getting 5 times the following line:

Successfuly ran! 5
Successfuly ran! 5
Successfuly ran! 5
Successfuly ran! 5
Successfuly ran! 5

it seems "i" is always 5, therefore the value of state1 gets overridden on every iteration

as a result I have only the following in the state1
{{ state1.value['5'].as_name }}

Screenshot 2022-03-14 at 22.33.53

Try the following:

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");
        },
      })
}

Simplified and testing again

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"

You simplified it but you didn't include the if statement...I will take another crack at this when I have time but here's why i is 5...

Because i is an integer and that's the last value of i.

Try
console.log("Successfully ran!",getAssigneeDetails.data.data.name[i] );

It's the last value of it, but it should be showing it as 0 on the first run and then 1,2,3,4 as it iterates over the for loop - isn't it?

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...

Hey, guys :wave:

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.