Multiple paginated GET API calls in parallel/async in Node Multiple paginated GET API calls in parallel/async in Node node.js node.js

Multiple paginated GET API calls in parallel/async in Node


I was able to get it working be creating a function with callback.

export function getFilesList() {  const foldersURL: any[] = [];  getFoldersFromRepo().then((response) => {    const values = response.values;    values.forEach((value: any) => {    //creating API URL for each folder in the repo      const URL = 'https://bitbucket.abc.com/stash/rest/api/latest/projects/'                   + value.project.key + '/repos/' + value.slug + '/files?limit=1000';      foldersURL.push(URL);        });    return foldersURL;      }).then((res) => {    // console.log('Calling all the URLS in parallel');    async.map(res, (link, callback) => {       const options = {         url: link,         auth: {           password: 'password',           username: 'username',         },       };      const myarray = [];// This function will consolidate response till the last Page per API.      consolidatePaginatedResponse(options, link, myarray, callback);     }, (err, results) => {       console.log('In err, results function');       if (err) {         return console.log(err);       }       //Consolidated results after all API calls.       console.log('results', results);     });  })   .catch((error) => error);}function consolidatePaginatedResponse(options, link, myarray, callback) {  request(options, (error, response, body) => {    const content = JSON.parse(body);    content.link = options.url;    myarray.push(content);    if (content.isLastPage === false) {      options.url = link + '&start=' + content.nextPageStart;      consolidatePaginatedResponse(options, link, myarray, callback);    } else {// Final response after consolidation per API      callback(error, JSON.stringify(myarray));    }  });}


I think the best way is to wrap it in a old school for loop (forEach doesn't work with async, since it's synchronous and it will cause all the requests to be spawn at the same time).

What I understood is that you do some sort of booting query where you get the values array and then you should iterate among the pages. Here some code, I didn't fully grasp the APIs so I'll give a simplified (and hopefully readable) answer, you should be able to adapt it:

export async function getFilesList() {    logger.info(`Fetching all the available values ...`);    await getFoldersFromRepo().then( async values => {        logger.info("... Folders values fetched.");        for (let i = 0; ; i++ ) {            logger.info( `Working on page ${i}`);            try {                // if you are using TypeScript, the result is not the promise but the succeeded value already                const pageResult: PageResult = await yourPagePromise(i);                if (pageResult.isLastPage) {                    break;                }            } catch(err) {                console.err(`Error on page ${i}`, err);                break;            }        }        logger.info("Done.");    });    logger.info(`All finished!`);}

The logic behind is that first getFoldersFromRepo() returns a promise which returns the values, and then I sequentially iterate on all available pages through the yourPagePromise function (which returns a promise). The async/await construct allows to write more readable code, rather then having a waterfall of then().

I'm not sure it respects your APIs specs, but it's the logic you can use as foundation! ^^