Julius Suominen Julius Suominen - 2 months ago 8
Node.js Question

Using the results of a GET request in Express router

First Node/Express app.

I'm having a hard time wrapping my head around on how to retrieve data from an endpoint and rendering it in the browser.

I have a dataservice.js that gets a JSON object from an endpoint like this:

const http = require('http');

getFinhockeyData = function() {

http.get('http://tilastopalvelu.fi/ih/modules/mod_standings/helper/standings.php?statgroupid=3545', (res) => {
console.log(`Got response: ${res.statusCode}`);

var body = "";

res.on('data', function (chunk) {
body += chunk;
})

res.on('end', function () {
var data = JSON.parse(body);
console.log('data parsed.');
console.log('first team name: ' + data.teams[0].TeamName);
console.log(typeof data);
return data;
})

}).on('error', (e) => {
console.log(`Got error from Finhockey: ${e.message}`);
});
}

module.exports.getFinhockeyData = getFinhockeyData;


Up until now things work and the
data
object can be console.logged and its content is usable.

The router.js looks currently like this:

'use strict';

const express = require('express');
const async = require('async');
const router = express.Router();
const dataservice = require('./dataservice.js')


router.get('/', function(req, res) {
async.series([
function(callback) {
getFinhockeyData(callback)
}
],
function(err, results) {
console.log('start rendering');
res.render('index', { data: data });
})
});

module.exports = router;


When I run the app and refresh the / route, I can see from the console that the
getFinhockeyData
is called and the data object's content is available in dataservice.js's console.logs, but the browser window hangs and the
res.render
part is never reached.

I understand that the rendering should be done only after the endpoint data request has finished (async.series usage), but it seems that I lack a fundamental understanding on how to actually use the result data from the getFinhockeyData function in the main route.

Any advice on this? I'll be happy to provide more info if necessary.

Answer

Firstly, doing the request is asynchronous, so you'll have to use either a callback or a promise.
Even the async middleware won't let you just return data from an asynchronous call, it requires a callback, but using native promises seems easier here

const http = require('http');

getFinhockeyData = function() {
  return new Promise( (resolve, reject) => {
    http.get('http://tilastopalvelu.fi/ih/modules/mod_standings/helper/standings.php?statgroupid=3545', (res) => {
      var body = "";

      res.on('data', function(chunk) {
        body += chunk;
      });

      res.on('end', function() {
        resolve( JSON.parse(body) );
      });

    }).on('error', reject);
  });
}

module.exports.getFinhockeyData = getFinhockeyData;

Also note that you're exporting as a module with a property

module.exports.getFinhockeyData = getFinhockeyData;

when you're going to use that in the routes, you have to use the property

const dataservice = require('./dataservice.js');

router.get('/', function(req, res) {
    dataservice.getFinhockeyData().then(function(data) {
        res.render('index', { data: JSON.stringify(data) }); 
    }).catch(function(err) {
        // epic fail, handle error here
    });
});