fabricatedmind
fabricatedmind

Reputation: 11

Express.js retrieving info from external API and rendering to site

I am kind of stuck on how to handle this solution. The frameworks I'm currently working with is node.js and express.js with pug for views/rendering html. What I am trying to do is render to a single page and use values from separate http get requests from different sites. I want express/node to query the external api's and render a view that I will retrieve via ajax call from the client side javascript. The ajax call using jquery from the client side I have figured out. My issue is how to handle multiple external API calls and place the results into an object to render in my pug view. I'm not sure what the best practice would be to execute this properly. Do I create a model? Also, how do I handle the asynchronous http gets? Use promises? I'm kind of new to node and javascript so I'm trying to see what the best conventions to use. I hope this makes sense.

Thanks!!!!

apiInfoModel.js

var apiCallInfo = {
    apiInfo1: APIDATA
    apiInfo2: APIDATA2
    apiInfo3: APIDATA3
}

Should I have a function that I call that would return the APIDATA?

apiCalls.js

function getApiInfo1() {
    return http.get
}

function getApiInfo2() {
    return http.get
}

function getApiInfo3() {
    return http.get
}

apiInfoController.js

var apiInfo = require('./apiInfoModel')
var apiCalls = require('./apiCalls')
exports.apiInfo = function(req,res,next){
    apiInfo.apiInfo1 = apiCalls.getApiInfo1
    apiInfo.apiInfo2 = apiCalls.getApiInfo2
    apiInfo.apiInfo3 = apiCalls.getApiInfo3
    res.render('apiInfo',{apiInfo: apiInfo})
}

Upvotes: 1

Views: 109

Answers (1)

shotor
shotor

Reputation: 1062

To expand on the comment by @Mauricio Noris Freire

apiCalls.js - Add callback parameters

function getApiInfo1(cb) {
    return cb(http.get)
}

function getApiInfo2(cb) {
    return cb(http.get)
}

function getApiInfo3(cb) {
    return cb(http.get)
}

apiInfoController.js - nest the callbacks to have access to all the results

var apiInfo = require('./apiInfoModel')
var apiCalls = require('./apiCalls')
exports.apiInfo = function(req,res,next){

    apiCalls.getApiInfo1(function(info1Result) {
        apiCalls.getApiInfo2(function(info2Result) {
            apiCalls.getApiInfo3(function(info3Result) {
                // now you have all 3 results
                apiInfoResult = {
                    apiInfo1: info1Result,
                    apiInfo2: info2Result,
                    apiInfo3: info3Result
                }
                res.render('apiInfo', { apiInfo: apiInfoResult })
            });
        });
    });
}

This nested structure is referred to as the pyramid of doom because it keeps growing with every asynchronous action you need to do. It can be improved by using a utility library like async https://www.npmjs.com/package/async:

    async.parallel( [
        apiCalls.getApiInfo1,
        apiCalls.getApiInfo2,
        apiCalls.getApiInfo3
    ], function(error, apiInfoResult) {
        apiInfoResult = {
            apiInfo1: info1Result,
            apiInfo2: info2Result,
            apiInfo3: info3Result
        }
        res.render('apiInfo', { apiInfo: apiInfoResult })
    });

But the currently recommended way is to use Promises. This is a new API introduced in JavaScript to handle this kind of situations. It's available in recent NodeJS versions. It removes the need for callbacks:

apiCalls.js - Return promises instead of using callbacks (the fetch library does this)

require('whatwg-fetch')

function getApiInfo1() {
    return fetch()
}

function getApiInfo2() {
    return fetch()
}

function getApiInfo3() {
    return fetch()
}

apiInfoController.js - Use Promise.all.

    const [
        apiInfo1, 
        apiInfo2, 
        apiInfo3
    ] = Promise.all([apiCalls.getApiInfo1, apiCalls.getApiInfo2, apiCalls.getApiInfo3]);

    apiInfoResult = { apiInfo1, apiInfo2, apiInfo3 }
    res.render('apiInfo', { apiInfo: apiInfoResult })

Upvotes: 1

Related Questions