fitMath
fitMath

Reputation: 23

return response data from async call

I created this function to get list all my drives from GDrive.

    async getAllDrives(token) {
        let nextPageToken = ""
        let resultArray = []        
        const config= {
            headers: {
                Authorization: `Bearer ${token}`
            }
        };
        const bodyParams = {            
            pageSize: 2,
            fields: 'nextPageToken, drives(id, name)',
            q:`hidden=false`,
        };
        do {
            axios.get(
                `https://www.googleapis.com/drive/v3/drives`,
                config,
                bodyParams,
            ).then(result => {
                nextPageToken = result.data.nextPageToken;  
                resultArray.push(result.data.drives);
                resultArray = resultArray.flat();                
                console.log("result", resultArray);
            }).catch(error => {
                console.log(error);
                //res.send(error);
            });
        }while(nextPageToken);
        resultArray = resultArray.flat();
        resultArray.map(drive => {
            drive.isSharedDrive = true;
        return drive;
        });
        return JSON.stringify(resultArray);
        
    }

When I look in console.log

then(result => {
                nextPageToken = result.data.nextPageToken;  
                resultArray.push(result.data.drives);
                resultArray = resultArray.flat();                
                console.log("result", resultArray);

            })

I have the expected result,

result [
  {
    kind: 'drive#drive',
    id: '**',
    name: ' ★ 🌩'
  },
]

but return JSON.stringify(resultArray); is empty. I found a similar question here, How do I return the response from an asynchronous call? but the answer is not satisfying.

Upvotes: 0

Views: 1027

Answers (3)

I recommend you study a little more about async/await.
It makes no sense for you to use async and put a .then().catch(), the purpose of async to get these encapsulated syntaxes.

async getAllDrives(token) {
  try {
    const getDrives = await this.request(token)
    console.log(getDrives)

    const results = this.resultArray(getDrives)
    return results
  } catch (e) {
    console.log(e)
  }
}

I didn't quite understand your while or your objective, adapt it to your code or remove it

async request(token) {
  let nextPageToken = 1 // ????????
  const config = {
    headers: {
      Authorization: `Bearer ${token}`
    }
  };
  const bodyParams = {            
    pageSize: 2,
    fields: 'nextPageToken, drives(id, name)',
    q: `hidden=false`,
  };
        
  let getDrives = [];
  // loop for each request and create a request array
  for (let x = 0; x < fields.nextPageToken; x++) { 
    const request = axios.get(
      `https://www.googleapis.com/drive/v3/drives`,
      config,
      bodyParams
    );
        
    getDrives.push(request)
  }
        
  const drives = await Promise.all(getDrives)
  return drives
}

async resultArray(drivers) {
  // result treatment here
}

The return of promise all will be an array of the driver's responses

Note: The response in request.data

const request = await axios.get()
const resposta = request.data

Read about https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Upvotes: 0

Tanaike
Tanaike

Reputation: 201553

I believe your goal is as follows.

  • You want to retrieve the drive list using axios.
  • Your access token can be used for retrieving the drive list using Drive API.

Modification points:

  • In order to use nextPageToken in the request, in this case, it is required to run the script with a synchronous process. So, async/await is used. This has already been mentioned in the existing answers.
  • When I saw your script, I thought that the query parameter might be required to be included in the 2nd argument of axios.get().
  • In order to use nextPageToken, it is required to include the property of pageToken. In your script, pageToken is not used. By this, the infinite loop occurs because nextPageToken is continued to be returned.

When these points are reflected in your script, how about the following modification?

Modified script:

let resultArray = [];
const config = {
  headers: {
    Authorization: `Bearer ${token}`,
  },
  params: {
    pageSize: 2,
    fields: "nextPageToken, drives(id, name)",
    q: `hidden=false`,
    pageToken: "",
  },
};
do {
  const { data } = await axios
    .get(`https://www.googleapis.com/drive/v3/drives`, config)
    .catch((error) => {
      if (error.response) {
        console.log(error.response.status);
        console.log(error.response.data);
      }
    });
  if (data.drives.length > 0) {
    resultArray = [...resultArray, ...data.drives];
  }
  nextPageToken = data.nextPageToken;
  config.params.pageToken = nextPageToken;
} while (nextPageToken);
resultArray.map((drive) => {
  drive.isSharedDrive = true;
  return drive;
});
return JSON.stringify(resultArray);

Testing:

When this script is run, the following result is obtained.

[
  {"id":"###","name":"###","isSharedDrive":true},
  {"id":"###","name":"###","isSharedDrive":true},
  ,
  ,
  ,
]

Note:

  • From the official document of "Drives: list",

    pageSize: Maximum number of shared drives to return per page. Acceptable values are 1 to 100, inclusive. (Default: 10)

    • So, when pageSize is 100, the number of loops can be reduced. If you want to test the loop using nextPageToken, please reduce the value.

References:

Upvotes: 0

koloml
koloml

Reputation: 525

You used the async call slightly incorrectly. You calling axios.get without await keyword, but with .then chaining. Since you don't wait for result to return, you getting empty array first, returning you nothing. And only then your callback function inside .then is getting called. To simplify, you doing this in your example:

function getAllDrives() {
    // Local variable where you want your result
    let result = [];
    
    // You calling the axios.get method, but don't wait for result
    axios.get().then(result => {})
    
    // Empty result is getting returned immediately
    return result;
}

And when response is returned from the remote server, function inside .then trying to save result to local variable. But function is already completed, so you don't get anything.

What you actually should do is call axios.get with await keyword:

// You should always cover your asynchronous code with a try/catch block
try {
    
    // Instead of `then` callback use `await` keyword. Promise returned from
    // this method will contain result. If error occurs, it will be thrown,
    // and you can catch it inside `catch`.
    const result = await axios.get(
        `https://www.googleapis.com/drive/v3/drives`,
        config,
        bodyParams
    );

    // Here is your code as you wrote it inside `then` callback
    nextPageToken = result.data.nextPageToken;
    resultArray.push(result.data.drives);
    resultArray = resultArray.flat();
    console.log("result", resultArray);
    
} catch (error) {
    
    // And here is your error handling code as you wrote it inside `catch`
    console.log(error);
    
}

This way your method will not complete until your request is not executed.

You can read more about async/await functions here.

Upvotes: 1

Related Questions