如何基于动态创建的请求数组执行多个axios获取请求

时间:2019-06-02 18:06:20

标签: node.js express promise axios

我正在尝试学习Angular / node和express。我目前正在尝试为其支持的端点编写一个

  1. 需要使用axios向外部API运行get请求,该请求将返回ID(数字)列表
  2. 对于提供的每个ID,都运行一个请求,该请求根据该ID获取详细信息。

但是我的问题是关于 2号。我有一个ID列表作为输入,我想根据每个ID对外部API(使用axios)运行一个请求。请注意,可能会有所帮助-根据ID向外部API的请求返回的对象包含该ID的详细信息,因此我对API端点的总体目标是返回对象数组,其中每个对象均包含ID的详细信息ID。

有几个类似我的问题...

  1. Pushing responses of axios request into array(与我的问题非常相似)
  2. Axios random number of requests

但是,他们正在使用React.js,而我很难将其解决方案适应于node / express。

我正在尝试根据第一个问题的顶部解答中提供的代码片段对我的方法进行建模。但是,我的解决方案是返回一个空对象作为响应。

我的问题:如何对外部API发出多个axios GET请求,我该怎么做?

app.route('/test').get((req, res) => {
    axios
        .get('https://www.thecocktaildb.com/api/json/v1/1/filter.php?i=vodka')//This will not be hardcoded, but grabbed as a parameter from the endpoint
        .then(function(response) {
            //Purpose of this initial .then() clause is to make a call to the cocktaildb API to get the IDs of all the cocktails with a given ingredient eg: vodka.

            var data = response.data;//response.data contains the JSON object containing the contents received by the cocktaildb API request.
            var cocktailIds = [];

            //collect all cocktail ids so we can later make more requests to obtain the details associated with that ID.
            data.drinks.forEach(drink => {
                cocktailIds.push(drink['idDrink']);
            });

            //this is passed on to the next then clause. It is a list of cocktail ids.
            return cocktailIds;
        })
        .then((drinks) => {
            //the promises variable contains a list of all the requests we will have to make in order to get the details of all cocktail ids. I have tested that they are valid requests.
            const promises = drinks.map(id => {
                //console.log(getCocktailDetailsUrl + id);
                return axios.get(getCocktailDetailsUrl + id)
                .then(({data}) => {
                    return data;
                })
            })
            
            //I was hoping Promise.All to execute all of the requests in the promise and response to be stored in the cocktailDetails variable
            const cocktailDetails = Promise.all(promises)
            .then(values => {
                return values;
            })
            .catch(error => {
                console.log("There was an error when sending requests for details of all cocktails");
                console.log(error);
            })

            //Sending response only formatted this way for testing purposes
            if(cocktailDetails) {
                //this block is executed, and an empty object is returned as response
                console.log("cocktails was sent as response");
                res.send(cocktailDetails);
            } else {
                console.log("cocktails was not sent as response");
                res.send("cocktailDetails was not poppulated at the time of sending response");
            }
        })
        .catch(function (error) {
            res.send("There was an iswsue with your request to the cocktaildb API.");
            console.log('The following is the error from the request to the cocktaildb API: ' + error);
        })
});

如前所述,我的回复包含一个空对象。我知道我必须以某种方式使用promise.all,但是我不确定如何正确实现它。

2 个答案:

答案 0 :(得分:0)

您应先等待诺言,然后再尝试发送回复。

await之前添加Promise.all,而您不需要then

const cocktailDetails = await Promise.all(promises)

答案 1 :(得分:0)

您的问题是,在发送响应之前,您没有等待所有诺言得到解决。其他批评,您的代码可以大大简化为以下内容:

app.route('/test').get((req, res) => {
    axios.get('https://www.thecocktaildb.com/api/json/v1/1/filter.php?i=vodka')//This will not be hardcoded, but grabbed as a parameter from the endpoint
    .then(function(response) {

        const promises = response.data.drinks.map(drink =>axios.get(getCocktailDetailsUrl + drink.idDrink).then(({data})=>data));

        //I was hoping Promise.All to execute all of the requests in the promise and response to be stored in the cocktailDetails variable
        return Promise.all(promises)
        .then(values => {
            res.send(values);// shouldn't you be using res.json() here?
        });//if an error is thrown for any reason here, it will be caught by your outer catch 
    })
    .catch(function (error) {
        res.send("There was an iswsue with your request to the cocktaildb API.");
        console.log('The following is the error from the request to the cocktaildb API: ' + error);
    });
});