最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to make multiple API calls using request in NodeJs? - Stack Overflow

programmeradmin3浏览0评论

Creating a simple Node.Js app where need to display data from two APIs, where both APIs returns multiple objects with an ID.

Need to display data from both these APIs on a single page, and somehow need to fetch the data from the two API based on the ID.

API 1 response looks like this:

    {
    "hikes": [
        {
            "id": 1,
            "active": true,
            "name": "Mt. Everest",          
        },
        {
            "id": 2,
            "active": true,
            "name": "K2",          
        },
        {
            "id": 3,
            "active": true,
            "name": "Mt. Kinley",          
        },
    ]
}

API 2 response looks like this:

{
    "hikes": [
        {
            "id": 1,
            "slots": 50,
            "available": 23,          
        },
        {
            "id": 2,
            "slots": 20,
            "available": 1,          
        },
        {
            "id": 3,
            "slots": 43,
            "available": 20,          
        },
    ]
}

Need to pull both APIs, fetch the data and render on a page to display "name", "slots", and "available".

This far managed to pull one of the APIs, and pass the data to a rendered index.ejs page, but I am not sure how I should pull the second API and some how fetch the data`s.

My code at the moment looks like this:

var port    = process.env.PORT || 3000,
    express = require("express"),
    request = require("request"),
    app = express();

app.set("view engine", "ejs");





var hikes = {
    url: "",
    headers: {
      'Identifier': identifier
    }
  };

  var availability = {
    url: "",
    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");
});

In my index.ejs, I for now have created a simple loop to print the names:

<% data["hikes"].forEach(function(hike){ %>

    <p><%= hike.name %></p>

<% }) %>

Any ideas on how to solve this?

Thanks!

Creating a simple Node.Js app where need to display data from two APIs, where both APIs returns multiple objects with an ID.

Need to display data from both these APIs on a single page, and somehow need to fetch the data from the two API based on the ID.

API 1 response looks like this:

    {
    "hikes": [
        {
            "id": 1,
            "active": true,
            "name": "Mt. Everest",          
        },
        {
            "id": 2,
            "active": true,
            "name": "K2",          
        },
        {
            "id": 3,
            "active": true,
            "name": "Mt. Kinley",          
        },
    ]
}

API 2 response looks like this:

{
    "hikes": [
        {
            "id": 1,
            "slots": 50,
            "available": 23,          
        },
        {
            "id": 2,
            "slots": 20,
            "available": 1,          
        },
        {
            "id": 3,
            "slots": 43,
            "available": 20,          
        },
    ]
}

Need to pull both APIs, fetch the data and render on a page to display "name", "slots", and "available".

This far managed to pull one of the APIs, and pass the data to a rendered index.ejs page, but I am not sure how I should pull the second API and some how fetch the data`s.

My code at the moment looks like this:

var port    = process.env.PORT || 3000,
    express = require("express"),
    request = require("request"),
    app = express();

app.set("view engine", "ejs");





var hikes = {
    url: "https://api./hikes",
    headers: {
      'Identifier': identifier
    }
  };

  var availability = {
    url: "https://api./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");
});

In my index.ejs, I for now have created a simple loop to print the names:

<% data["hikes"].forEach(function(hike){ %>

    <p><%= hike.name %></p>

<% }) %>

Any ideas on how to solve this?

Thanks!

Share Improve this question edited Sep 24, 2018 at 18:21 objectclass asked Sep 18, 2018 at 12:51 objectclassobjectclass 2241 gold badge6 silver badges20 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 1

If I understood correctly, I assume you are trying to fetch data from two APIs and want to merge the data into single array of objects based on object id and pass it to view. if this is the case then you can use https://www.npmjs./package/async to fetch data parallel from both the APIs then merge the data in to one array of objects and pass it to your view. Following code will help you understand the implementation.

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./hikes",
  headers: {
   'Identifier': identifier
  }
};

var availability = {
  url: "https://api./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");
});

There are two possible options for creating your page:

  • cache answers from both apis
  • proxy requests to them

You need chose what will you use.

For cache use setInterval to store the answer into two variables objects each 5/60/N seconds.

For proxy use async/await approach and Promise.all to continue work after your have both answers. In this case I propose change request package to got

I would request you to read about Promise, and asynchronous function more for better understanding and solution.

For now this will work for you:

var hikes = {
    url: "https://api./hikes",
    headers: {
      'Identifier': identifier
    }
};

var availability = {
    url: "https://api./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>

<% }) %>

Better Solution

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./hikes",
    headers: {
      'Identifier': identifier
    }
};

var availability = {
    url: "https://api./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);
    };
});

better 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>

        <% } %>
    <% } %>
<% } %>

Concept solved with multiple request functions. result, multiple desired api values are able to be accessed by global variable. node 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/";

Solution starts here:

//assign api to constant
const btcUsd = "https://apiv2.bitcoinaverage./indices/global/ticker/BTCUSD";
const trxBtc = "https://apiv2.bitcoinaverage./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();

The desired api values btc and trx can now be used by any rendered view that assign each value to an object key:

// render view
app.get("/", function(req, res){
 res.render(views + "pages/index", {btcTicker: btc, trxTicker: trx});
});

In view:

<h1> <%= btcTicker %> </h1>
<br>
<h1> <%= trxTicker %> </h1>
发布评论

评论列表(0)

  1. 暂无评论