推荐的模式来遍历API响应,直到用尽?

时间:2019-10-01 18:50:30

标签: node.js axios

我是Node和异步编程模型的新手。我在处理在同步环境中看起来很基本的简单要求时遇到了问题:通过API响应进行分页直到响应为空。

更具体地说,API在成功调用后将返回数据,并且状态为200或206(部分内容)。如果看到206响应,则需要继续调用API(还会发送每次递增的page查询参数),直到看到200响应为止。

在同步语言中,任务将是小菜一碟:

// pseudocode
data = []
page = 1
do {
    response = api.call(page)
    data.append(response.data)
    page++
} while (response != 200)

return data

现在,在Node中,对于单个api调用,这样的代码将起作用:

// fire when '/' has a GET request
app.get('/', (req, res) => {
    axios.get('https://api.com/v1/cats')
        .then(response => {
            // now what??
        });
    });
});

看到//now what??评论吗?这就是我想知道如何进行的地方。我碰到了this有点相关的帖子,但是无法将其转换为适用于Node和Axios的格式。

仅将axios代码包装在单独的函数中是否足够?我不这么认为,因为如果我这样做:

function getData(pageNum) {
    axios.get('https://api.com/v1/cats')
        .then(response => {
            // now what??
        });
    });
}

我不能依赖返回值,因为一旦执行axios.get(),函数便结束了。得到第一个响应后,我可以再次调用getData(),但是,假设我想将这些多个调用中的所有数据作为我的Express服务器的HTTP响应返回。 。 。我该怎么办?

我希望我不会因懒惰或其他原因而感到失望。我确实环顾四周,但没有发现任何相关内容。

1 个答案:

答案 0 :(得分:1)

首先,一个反问:数据集太大了,您需要担心用完所有内存吗?因为如果是这样,那么将需要更多的工作来以完全流式传输数据的方式来构造代码。 (实际上,我什至不确定express是否允许流式传输...您使用的不是吗?)

从axios文档中,看来response是可读的流,提供了响应正文。因此,阅读它也是一个异步任务。因此,您应该编写一个执行此操作的函数。有关更多详细信息,请参见nodejs文档的“ Stream”页面。或者,如果时间允许,也可以说服我为您提供帮助。但是现在,我假设您有一个函数readResponse,该函数将axios响应对象作为参数并返回一个Promise,并且Promise解析为诸如{ statusCode: 206, result: ['thing1', 'thing2'] }之类的对象。我还将假设您的目标是获取所有result数组并将它们连接在一起以获得例如['thing1', 'thing2', 'thing3', 'thing4', 'thing5', 'thing6']

您可以编写getData函数的自调用版本。将从指定页面开始(而不是页面本身)检索所有数据:

function getData(pageNum) {
    axios.get('https://api.com/v1/cats' + (pageNum ? '?page=' + pageNum) : '')
        .then(readResponse)
        .then(function(parsedResponse) {
            if(parsedResponse.statusCode == 200) {
                return parsedResponse.result;
            } else if(parsedResponse.statusCode == 206) {
                return getData(pageNum + 1).then(function(laterData) {
                    return parsedResponse.result.concat(laterData);
                });
            } else {
                // error handling here, throw an exception or return a failing promise.
            }
        });
    });
}

然后,要获取所有数据,只需使用pageNum = 0调用此函数:

// fire when '/' has a GET request
app.get('/', (req, res) => {
    getData(0)
        .then(function(results) {
            // results is now the array you want.
            var response = JSON.stringify(results);   // or whatever you're doing to serialise your data
            res.send(response);
        });
});