1

For my class, my professor wants us to create a simple node.js web site that reads a text file containing a fully qualified URL and then use the URL to retrieve JSON data from a remote web site and finally save the retrieved JSON to another text file. He wants the URL stored in a global variable.

I've done this, with a hardcoded URL, the one that's supposed to be read from the file. That runs fine and does what I want. My problem is when I try to create a global variable for the URL, it always returns undefined. I know it's a timing issue because the file is not being read asynchronously, but I can't figure out how to fix it.

'use strict';
// load the built-in http module
let http = require('http');
// load the add-in express module
let express = require("express");
// load the add-in xmlhttprequest and create XMLHttpRequest object
let XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
// create app object from express() constructor
let app = express();
// create a port number
let port = process.env.PORT || 3000;
let fs = require('fs');

// create a "get" event handler function
// request and response object references (req, res)
function getJSON() {
    app.get("/", function (reqNode, resNode) {
        var test = new Promise(function (resolve, reject) {
            var req = new XMLHttpRequest();
            req.open('GET', 'http://gd2.mlb.com/components/game/mlb/year_2017/month_07/day_08/master_scoreboard.json');
            req.onload = function () {
                if (req.status === 200) {
                    resolve(req.responseText);
                }
                else {
                    reject(req.statusText);
                }
            }
            req.onerror = function () {
                reject("network error");
            };

            req.send();
        });

        test.then(
            function (response) {
                // display in browser on success
                resNode.send('JSON data saved to file.');
            },
            function (error) {
                console.error("Request failed: ", error);
            }
        ),
            test.then(
                function (response) {
                    // write the response to json.txt
                    fs.writeFile('json.txt', response, function (err) {
                        if (err) {
                            console.log(err);
                        }
                        else {
                            console.log('JSON data saved to file.');
                        }
                    });
                },
                function (error) {
                    console.log(error);
                }
            ),
            test.catch(
                error => console.log(error)
            )
    });
}

(function () {
    // create a server object
    let server = http.createServer(app);

    // listen on specified port for get requests
    server.listen(port);
    // call getJSON function
    getJSON();
})();

This code works with a hardcoded URL, but I need a function to store it in a global variable instead.

Dependencies:

"dependencies": {
    "express": "^4.17.1",
    "xmlhttprequest": "^1.8.0"
  }

And, the async/await that I tried. The 'url' variable returns as undefined, so this doesn't work. There are no errors returned, but localhost fails to load.

'use strict';
// load the built-in http module
let http = require('http');
// load the add-in express module
let express = require("express");
// load the add-in xmlhttprequest and create XMLHttpRequest object
let XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
// create app object from express() constructor
let app = express();
// create a port number
let port = process.env.PORT || 3000;
let fs = require('fs');

function readTxt() {
    fs.readFile('urls.txt', { encoding: 'utf-8' }, function (err, data) {
        if (err) {
            console.log('Error reading file: ' + err)
        }
        else {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    resolve(data);
                }, 3000)
            });
        }
    });
}


// create a "get" event handler function
// request and response object references (req, res)
async function getJSON() {
    let url = await readTxt();
    console.log(url);
    app.get("/", function (reqNode, resNode) {
        var test = new Promise(function (resolve, reject) {
            var req = new XMLHttpRequest();
            req.open('GET', url);
            req.onload = function () {
                if (req.status === 200) {
                    resolve(req.responseText);
                }
                else {
                    reject(req.statusText);
                }
            };

            req.onerror = function () {
                reject("network error");
            };

            req.send();
        });

        test.then(
            function (response) {
                // display in browser on success
                resNode.send('JSON data saved to file.');
            },
            function (error) {
                console.error("Request failed: ", error);
            }
        ),
            test.then(
                function (response) {
                    // write the response to json.txt
                    fs.writeFile('json.txt', response, function (err) {
                        if (err) {
                            console.log(err);
                        }
                        else {
                            console.log('JSON data saved to file.');
                        }
                    });
                },
                function (error) {
                    console.log(error);
                }
            ),
            test.catch(
                error => console.log(error)
            )
    });
}

(async function () {
    // create a server object
    let server = http.createServer(app);

    // listen on specified port for get requests
    server.listen(port);
    // call getJSON function
    getJSON();
})();

I don't believe this is a duplicate. I looked at other questions, I tried using async/await(code above), as answered to this question: https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call. That would likely work, but I'm having trouble getting it set up properly. Thanks in advance!

2
  • You should provide the code which fails, proof of failure (like error that you get in console) and the expectation you have from the code. Commented Dec 2, 2020 at 19:36
  • I'll do that. Thanks. Commented Dec 2, 2020 at 19:38

1 Answer 1

1

Your implementation of readTxt function is wrong. Here's the correct implementation of it. I have added comments to describe how to use promises.

function readTxt() {
    // return a promise from the function
    return new Promise(function (resolve, reject) {
      // do the asynchronous operation
      fs.readFile('urls.txt', { encoding: 'utf-8' }, function (err, data) {
        if (err) {
            console.log('Error reading file: ' + err)
            // reject the promise in case of error
            reject(err);
        }
        else {
            setTimeout(function () {
                // resolve the promise after successfull execution of asynchronous code
                resolve(data);
            }, 3000)
        }
    });
}
Sign up to request clarification or add additional context in comments.

7 Comments

Okay, I thought this worked and then realized, I never removed the hardcoded URL. When ran, the URL is read correctly (can tell from console), but now I get an error404 saying " GET localhost:3000 404 (Not Found) ".
Looks like the url here is "localhost:3000" or maybe undefined so it depends on what you want the url to be. But that would be another question. Questions on stackoverflow are encouraged to be specific to be made easier to answer and provide value to future readers.
You should delete this comment then, as it is not the correct answer. I wasn't having problems with that before using the code you provided.
Well, to answer my own question, just had to define host as '127.0.0.1' and add it to the server.listen parameter. Then it worked.
Your question was regarding you not being able to read the file asynchronously. And as you mentioned, the code provided in the answer allows reading the file. So how is it not the correct answer?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.