![](/img/trans.png)
[英]How can I make multiple API calls to save all results in one json file using Nodejs?
[英]How to make multiple API calls using request in NodeJs?
创建一个简单的Node.Js
应用程序, Node.Js
应用程序需要显示来自两个API的数据,其中两个API均返回具有ID的多个对象。
需要在单个页面上显示这两个API的数据,并且需要以某种方式基于ID从这两个API提取数据。
API 1响应如下所示:
{
"hikes": [
{
"id": 1,
"active": true,
"name": "Mt. Everest",
},
{
"id": 2,
"active": true,
"name": "K2",
},
{
"id": 3,
"active": true,
"name": "Mt. Kinley",
},
]
}
API 2响应如下所示:
{
"hikes": [
{
"id": 1,
"slots": 50,
"available": 23,
},
{
"id": 2,
"slots": 20,
"available": 1,
},
{
"id": 3,
"slots": 43,
"available": 20,
},
]
}
需要同时提取两个API,获取数据并在页面上呈现以显示“名称”,“插槽”和“可用”。
到目前为止,我们设法提取了一个API,并将数据传递到呈现的index.ejs
页面,但是我不确定应该如何提取第二个API,以及某些如何获取数据。
目前,我的代码如下所示:
var port = process.env.PORT || 3000,
express = require("express"),
request = require("request"),
app = express();
app.set("view engine", "ejs");
var hikes = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
var availability = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
app.get("/", function(req, res){
function callback(error, response, body){
if(!error && response.statusCode == 200){
var data = JSON.parse(body);
res.render("index", {data: data});
})
}
}
request(hikes, callback);
});
app.listen(port, function(){
console.log("Running");
});
我现在在index.ejs中创建了一个简单的循环来打印名称:
<% data["hikes"].forEach(function(hike){ %>
<p><%= hike.name %></p>
<% }) %>
关于如何解决这个问题的任何想法?
谢谢!
如果我理解正确,我假设您正在尝试从两个API中获取数据,并希望根据对象ID将数据合并到单个对象数组中并将其传递给视图。 如果是这种情况,则可以使用https://www.npmjs.com/package/async从两个API并行获取数据,然后将数据合并到一个对象数组中并将其传递给视图。 以下代码将帮助您理解实现。
var port = process.env.PORT || 3000,
express = require("express"),
request = require("request"),
app = express();
var async = require('async');
app.set("view engine", "ejs");
var hikes = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
var availability = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
app.get("/", function(req, res) {
function callback(error, response, body, cb) {
if(error || response.statusCode != 200)
return cb(true);
cb(null, JSON.parse(body).hikes);//instead of sending data directly to view, send it to async callback to merge it latter
}
var tasks = { // tasks to run in parallel
hikes: function (cb) {
request(hikes, function (error, response, body) {
callback(error, response, body, cb);
});
},
availability: function (cb) {
request(availability, function (error, response, body) {
callback(error, response, body, cb);
});
}
};
async.parallel(tasks, function (err, resp) {
if(err) {
//handle error here, the error could be caused by any of the tasks.
return;
}
var availabilityIdMap = resp.availability.map(function (availability) { return availability.id; });//get an array of all the availability ids
var data = resp.hikes.map(function (hike) { //merging hike to corresponding availability object
var availabilityIndex = availabilityIdMap.indexOf(hike.id); // finding the availability against the hike id.
if(availabilityIndex < 0) //availability not found, just return hike
return hike;
var matchingAvailabilityObj = resp.availability[availabilityIndex]; //get the matching availability object
var mergedObj = Object.assign(hike, matchingAvailabilityObj); //merge both objects
return mergedObj;
});
// now the data will have an array of merged object with properties from hike and availability objects
res.render("index", {data: data});
});
});
app.listen(port, function(){
console.log("Running");
});
创建页面有两种可能的选择:
您需要选择要使用的内容。
对于缓存,请使用setInterval
将答案存储在每个5/60 / N秒的两个变量对象中。
对于代理,请使用async / await方法和Promise.all
,在得到两个答案后继续工作。 在这种情况下,我建议改变request
包了
谢谢您的回复!
有人在类似案例中有任何示例代码吗? 在上述两个方面中,我认为代理将是最适合我的应用程序的。
您将如何一起获取数据并传递到呈现的页面? 在合并数据的地方创建一个新的数组或类似的数组?
我希望您阅读有关Promise和异步功能的更多信息,以便更好地理解和解决。
现在,这将为您工作:
var hikes = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
var availability = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
app.get("/", function(req, res){
function callback(error, response, body){
if(!error && response.statusCode == 200){
var data = JSON.parse(body);
request(availability, (err, response, body) => {
if(!err && response.statusCode == 200){
var data2 = JSON.parse(body);
res.render("index", {data1: data, data2: data2});
}
});
}
}
request(hikes, callback);
});
index.ejs
:
<% data1["hikes"].forEach(function(hike){ %>
<p><%= hike.name %></p>
<% }) %>
<% data2["availability"].forEach(function(available){ %>
<p><%= available.slots %></p>
<p><%= available.available %></p>
<% }) %>
更好的解决方案
function apiCall (reqOps) {
return new Promise ( (resolve, reject) => {
request(reqOps, (err, res, body) => {
if(!error && response.statusCode == 200){
resolve( JSON.parse(body) );
}
reject(err);
});
});
}
var hikes = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
var availability = {
url: "https://api.com/hikes",
headers: {
'Identifier': identifier
}
};
app.get("/", function(req, res){
let data1, data2;
apiCall(hikes)
.then( result => { // Result of first call
data1 = result;
return apiCall(availability);
})
.then( result => { // Result of second call
data2 = result;
res.render("index", {data1, data2});
})
.catch( err => {
console.log("Error occured in one of the API call: ", err);
});
});
// or with async-await
app.get("/", async function(req, res){
try {
let data1 = await apiCall(hikes);
let data2 = await apiCall(availability);
data1 = JSON.parse(data1);
data2 = JSON.parse(data2);
res.render("index", {hikes: data1.hikes, availability: data2.availability});
}
catch( err ) {
console.log("Error occured in one of the API call: ", err);
};
});
更好的index.ejs
:
<% if (hikes.length>0) { %>
<% if (availability.length>0) { %>
<% for (var i = 0; i < hikes.length; i++) { %>
<p><%= hikes[i].name %></p>
<p><%= availability[i].slots %></p>
<p><%= availability[i].available %></p>
<% } %>
<% } %>
<% } %>
通过多个请求功能解决了概念。 结果,可以通过全局变量访问多个所需的api值。 节点v10.15.1:
// require node packages
const express = require("express");
const bodyParser = require("body-parser");
const request = require("request");
//set app to use express package
const app = express();
//let app use body-parser package
app.use(bodyParser.urlencoded({extended:true}));
// let app set ejs as the view engine
app.set("view engine", "ejs");
// set view path
const view = __dirname + "/app/views/";
解决方案从这里开始:
//assign api to constant
const btcUsd = "https://apiv2.bitcoinaverage.com/indices/global/ticker/BTCUSD";
const trxBtc = "https://apiv2.bitcoinaverage.com/indices/tokens/ticker/TRXBTC";
// function containing api parser
function tickers(){
request(btcUsd, function(error, response, body){
// handle errors if any
if(error){
console.log(error);
} else {
// parse json
let data = JSON.parse(body);
// get last price
btc = (data.last).toFixed(2);
console.log(btc);
}
});
request(trxBtc, function(error, response, body){
// handle errors if any
if(error){
console.log(error);
} else {
// parse json
let data = JSON.parse(body);
// get last price
usdConvert = (data.last) * btc;
trx = usdConvert.toFixed(4);
console.log(trx);
}
});
}
// function to trigger ticker function and set interval. (this is optional)
function getTickers(){
tickers();
// set interval
setInterval(tickers, 60000);
}
//activate getTickers function
getTickers();
现在,任何将每个值分配给对象键的渲染视图都可以使用所需的api值btc和trx:
// render view
app.get("/", function(req, res){
res.render(views + "pages/index", {btcTicker: btc, trxTicker: trx});
});
鉴于:
<h1> <%= btcTicker %> </h1>
<br>
<h1> <%= trxTicker %> </h1>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.