Node 中 parallel/async 中的多个分页 GET API 调用

Multiple paginated GET API calls in parallel/async in Node

我正在调用 bitbucket API 以获取存储库中的所有文件。我已经达到了可以获取回购中所有文件夹的列表并并行地对回购中的所有根文件夹进行第一个 API 调用并获取所有前 1000 个文件的列表的地步文件夹。

但问题是 bitbucket api 一次只能给我每个文件夹 1000 个文件。

我需要附加一个查询参数 &start =nextPageStart 并再次调用,直到它为空并且 isLastPage 根据 API 为真。我怎样才能用下面的代码实现它?

我从第一次调用 api 得到了 nextPageStart。请参阅下面的 API 回复。

下面是我目前的代码。

感谢任何帮助或指导。

Response from individual API thats called per folder.

{
    "values": [
        "/src/js/abc.js",
        "/src/js/efg.js",
        "/src/js/ffg.js",
        ...
    ],
    "size": 1000,
    "isLastPage": false,
    "start": 0,
    "limit": 1000,
    "nextPageStart": 1000
}

function where i made asynchronous calls to get the list of files

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',
         },
       };
       request(options, (error, response, body) => {

      // TODO: How do I make the get call again so that i can paginate and append the response to the body till the last page.

         callback(error, body);
       });
     }, (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);
}

我认为最好的方法是将它包装在老派的 for 循环中(forEach 不适用于异步,因为它是同步的,它会导致所有请求同时产生)。

我的理解是,您在获得 values 数组的地方执行某种启动查询,然后您应该在页面之间进行迭代。这里有一些代码,我没有完全掌握 API,所以我会给出一个简化的(希望可读的)答案,你应该能够适应它:

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!`);

}

背后的逻辑是,首先 getFoldersFromRepo() returns 一个 returns 值的承诺,然后我通过 yourPagePromise 函数顺序迭代所有可用页面( returns 一个承诺)。 async/await 构造允许编写更具可读性的代码,而不是使用 then() 的瀑布。

我不确定它是否符合您的 API 规范,但它是您可以用作基础的逻辑! ^^

我能够通过创建带有回调的函数来让它工作。

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