我正在使用NodeJS
和Express
开发一款应用。此应用程序的目标是提供从多个不同API端点获取的数据,所有这些都在一个页面中。
不幸的是,我对NodeJS
和Express
相对较新,但已经做了一些研究,我知道你可以用多个异步请求
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"
}
}
]
}
非常感谢任何帮助。提前致谢并快乐编码!
答案 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
});