Как сделать несколько вызовов API, используя запрос в NodeJs? - PullRequest
0 голосов
/ 18 сентября 2018

Создание простого Node.Js приложения, в котором необходимо отображать данные из двух API, где оба API возвращают несколько объектов с идентификатором.

Необходимо отобразить данные обоих API на одной странице и каким-то образом получить данные из двух 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 голосов
/ 18 февраля 2019

Концепция решена с несколькими функциями запроса. результат, несколько желаемых значений 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>
0 голосов
/ 23 сентября 2018

Если я правильно понял, я предполагаю, что вы пытаетесь получить данные из двух API и хотите объединить данные в один массив объектов на основе идентификатора объекта и передать его для просмотра. в этом случае вы можете использовать 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");
});
0 голосов
/ 19 сентября 2018

Спасибо за ваш ответ!

У кого-нибудь есть пример кода на подобный случай?Я думаю, что из двух приведенных выше прокси лучше всего подойдет для моего приложения.

Как бы вы собрали данные вместе и перешли на отображаемую страницу?Создать новый массив или аналогичный, где вы объединяете данные?

0 голосов
/ 19 сентября 2018

Я бы попросил вас прочитать о 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>

        <% } %>
    <% } %>
<% } %>
0 голосов
/ 18 сентября 2018

Существует два возможных варианта создания страницы:

  • кеширование ответов от обоих apis
  • запросов прокси к ним

Вам нужно выбрать, чтоВы будете использовать.

Для кеш используйте setInterval для хранения ответа в двух переменных объектах каждые 5/60 / N секунд.

Для прокси используйте подход async / await и Promise.all для продолжения работы после получения обоих ответов.В этом случае я предлагаю изменить request пакет на получил

...