如何使用NodeJ中的请求进行多个API调用?

时间:2018-09-18 12:51:58

标签: javascript node.js ecmascript-6 request ejs

创建一个简单的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>

<% }) %>

关于如何解决此问题的任何想法?

谢谢!

5 个答案:

答案 0 :(得分:1)

如果我理解正确,我假设您正在尝试从两个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");
});

答案 1 :(得分:0)

创建页面有两种可能的选择:

  • 缓存两个API的答案
  • 代理请求给他们

您需要选择要使用的内容。

对于缓存,请使用setInterval将答案存储在两个变量对象中,每5/60 / N秒。

对于代理,请使用async / await方法和Promise.all,在得到两个答案后继续工作。在这种情况下,我建议将request包更改为got

答案 2 :(得分:0)

谢谢您的回复!

有人在类似情况下有任何示例代码吗?在以上两个方面中,我认为代理将是最适合我的应用程序的。

您将如何一起获取数据并传递到呈现的页面?在合并数据的地方创建一个新的数组或类似的数组?

答案 3 :(得分:0)

我希望您阅读有关Promise和异步功能的更多信息,以便更好地理解和解决问题。

现在这对您有效:

var loadingDots = Enzyme.render();

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

答案 4 :(得分:0)

通过多个请求功能解决了概念。结果,可以通过全局变量访问多个所需的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>