Express - 来自不同端点的多个异步请求

时间:2016-12-14 23:43:33

标签: javascript json node.js express async.js

我正在使用NodeJSExpress开发一款应用。此应用程序的目标是提供从多个不同API端点获取的数据,所有这些都在一个页面中。

不幸的是,我对NodeJSExpress相对较新,但已经做了一些研究,我知道你可以用多个异步请求 async模块。但是,我不太确定如何解决这个问题,需要你的帮助才能让我回到正轨。

我需要提供两个异步请求来获取所有预期的数据,并最终将它们作为一个JSON链接在一起。 requets如下:

请求1 - 今晚的比赛

首先,我需要获得今晚的预定游戏(http://exampleapi.com/api/v1/schedule) 此API端点输出的JSON数据如下:

{
  "date": "2016-12-15",
  "totalGames": 3,
  "games": [
     {
       "id": 1,
       "link": "/api/v1/game/1"
     },
     {
       "id": 2,
       "link": "/api/v1/game/2"
     },
     {
       "id": 3,
       "link": "/api/v1/game/3"
     }
  ]
}

在下面,我的文件中有一条路线以上述方式输出提取的JSON

旁注/问题for循环迭代超过3次,第一个对象将输出三次,而不是三个不同的对象。

server.js

router.get('/test/schedule_test', function(req, res) {

    res.contentType('application/json'); // content type of the response object
    var url = 'http://exampleapi.com/api/v1/schedule'; // url of the api endpoint

    // make an request to the endpoint
    request(url, function (error, response, body) {

        // If the request was successfully made
        if (!error && response.statusCode == 200) {

            var body = JSON.parse(body);
            var schedule, totalGames, date, games = [], id, link, game;

            // Schedule object
            schedule = {
                "totalGames": totalGames,
                "date": date,
                "games": games
            };
            schedule.totalGames = body.totalGames;
            schedule.date = body.dates[0].date;
            game = {"id": id, "link": link};

            for(var i = 0; i < schedule.totalGames; i++) {
                // Here's the part where I think I've made some mistakes and why it outputs a single object over so many times the value of "totalGames" is.
                game.id = body.dates[0].games[i].gamePk;
                game.link = body.dates[0].games[i].link;

                games.push({
                    "game": game
                });
            }
            res.status(200).json(schedule);

        } else {
            res.status(404).json({"error": true});
        }
    });
});

接下来,我需要为link属性值提供的每个链接发出异步请求,以获取每个参与团队的团队相关数据。

请求2 - 与团队相关的数据

此API端点的预期JSON输出如下:

{
  "gameData": {
    "teams": {
      "away": {
        "link": "/api/v1/teams/1",
        "name": "Example team 1",
        "abbreviation": "EXT1"
       },

       "home": {
         "link": "/api/v1/teams/2",
         "name": "Example team 2",
         "abbreviation": "EXT2"    
        }
    },
    "venue": {
      "name": "Georgestown Palace, Manitoba"
    }
  }
}

在下面,我的文件中有一条路线以上述方式输出提取的JSON

server.js

router.get('/test/team_test', function(req, res) {

    // Note that these urls should be generated dynamically from the previous request
    var urls = [
        'http://exampleapi.com/api/v1/teams/1',
        'http://exampleapi.com/api/v1/teams/2'
    ];

    async.map(urls, function(url, callback) {
        // iterator function
        request(url, function (error, response, body) {

            if (!error && response.statusCode == 200) {
                // do any further processing of the data here
                var body = JSON.parse(body);
                var teams;

                // Away team
                var away_link, away_name, away_abbr;
                var away = {"link": away_link, "name": away_name, "abbreviation": away_abbr};

                var away_link = body.gameData.teams.away.link;
                away.link = away_link;

                var away_name = body.gameData.teams.away.name;
                away.name = away_name;

                var abbreviation = body.gameData.teams.away.abbreviation;
                away.abbrreviation = abbreviation;

                // Home team
                var home_link, home_name, home_abbr;
                var home = {"link": home_link, "name": home_name, "abbreviation": home_abbr};

                var home_link = body.gameData.teams.home.link;
                home.link = home_link;

                var home_name = body.gameData.teams.home.name;
                home.name = home_name;

                var home_abbreviation = body.gameData.teams.home.abbreviation;
                home.abbreviation = home_abbreviation;

                var arena = body.gameData.venue.name;

                teams = {
                    "teams": {
                        "away": away,
                        "home": home
                    },
                    "played_at": arena

                };

                callback(null, teams);

            } else {
                callback(error || response.statusCode);
            }
        });
    }, function(err, results) {

        // completion function
        if (!err) {
            res.contentType('application/json');
            res.status(200).json(results);
        } else {
            // handle error here
            console.log(err);
        }
    });
});

预期结果

最后,我需要将这两个不同的输出连接到一个JSON输出中。预期的结果看起来像这样:

{
  "date": "2016-12-15",
  "totalGames": 3,
  "games": [
     {
       // #1 joined object

       // data from the first api request
       "id": 1,
       "link": "/api/v1/game/1",

       // data from the second api request
       "teams": {
          "away": {
            "link": "/api/v1/teams/1",
            "name": "Example team 1",
            "abbreviation": "EXT1"
          },
          "home": {
            "link": "/api/v1/teams/2",
            "name": "Example team 2",
            "abbreviation": "EXT2"    
           }
        },
        "venue": {
          "name": "Georgestown Palace, Manitoba"
        }
     },


     {
       // #2 joined object
       "id": 2,
       "link": "/api/v1/game/3",
       "teams": {
          "away": {
            "link": "/api/v1/teams/3",
            "name": "Example team 3",
            "abbreviation": "EXT3"
          },
          "home": {
            "link": "/api/v1/teams/4",
            "name": "Example team 4",
            "abbreviation": "EXT4"    
           }
        },
        "venue": {
          "name": "Portsmouth Valley, New Jersey"
        }
     },

     {
       // #3 joined object
       "id": 3,
       "link": "/api/v1/game/3",
       "teams": {
          "away": {
            "link": "/api/v1/teams/5",
            "name": "Example team 5",
            "abbreviation": "EXT5"
          },
          "home": {
            "link": "/api/v1/teams/6",
            "name": "Example team 6",
            "abbreviation": "EXT6"    
           }
        },
        "venue": {
          "name": "Colorado Springs, Colorado"
        }

     }

  ]

}

非常感谢任何帮助。提前致谢并快乐编码!

1 个答案:

答案 0 :(得分:0)

为了协调多个异步操作,我强烈建议你使用promises。如果您使每个异步操作都返回一个promise,那么您可以使用Promise.all()知道它们何时完成,并且可以访问每个异步操作所获取的数据。

例如,如果您有一个想要从中获取数据的端点数组,则可以这样做:

const request = require('request');

// promisify the request module
function requestAsync(url) {
    return new Promise(function(resolve, reject) {
        request(url, function(err, response, body) {
            if (err) {
                reject(err);
            } else if (response.statusCode !== 200) {
                reject(new Error("response.statusCode = " + response.statusCode));
            } else {
                resolve(body);
            }
        });
    });
}


function getData(endpoints) {
    return Promise.all(endpoints.map(function(url) {
        return requestAsync(url);
    }));
}

let endpoints = [...];    // multiple endpoints to retrieve data from
getData(endpoints).then(function(results) {
    // results array contains all the results you can process here in the
    // order they appears in the array.
    // You can now organize the returned data into the final format you want here
}).catch(function(err) {
    // error occurred here
});