Search code examples
javascriptnode.jsexpressrouteshtml-rendering

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.


Solution

  • 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
        });
    });