Ryder
Ryder

Reputation: 21

Node.js || How to write a file, then read it once it finishes writing?

I am fairly new to node.js and I'm still learning my way around coding in general.
The following things are what I'm trying to accomplish...

[*]Request data from api.

[*]Write the data into a new JSON file.

[*]Read the newly written file.

[*]Extract specific information.

This is what I have going for me so far

let     request = require('request'),
        fs = require('fs'),
        DATA = require('./DATA.json'),
        url = "https://dataThatIAmTryingToGet";


        request(url, (error, response, body)=> {
          if (!error && response.statusCode === 200) {
            fs.writeFile("./DATA.json", (body))
          } else {
            console.log("Got an error: ", error, ", status code: ", response.statusCode)
          }
        });

        if (fs.existsSync("./DATA.json")){
            fs.readFile("./DATA.json", (err, data) => {
                if (err) {
                    console.log("Whoopsiedaisy");
                } else {
                    console.log("You did it nerd");
                    console.log(DATA.response.items.length);
                }
            })
        };

With this code I accomplish the first two off my checklist...

[X]Request data from api.

[X]Write the data into a new JSON file.

[*]Read the newly written file.

[*]Extract specific information.

The console is printing You did it nerd, but the error I am getting is that console.log(DATA.response.items.length); is returning undefined in the console. Im trying to see how many specific items fall under items in the api. (Example of the api below). My issue is that I'm not sure if it's because the file is being read too fast, or if I'm trying to read the data incorrectly.

Here is an example of the api output...

{
    "response": {
        "success": 1,
        "current_time": 1488743993,
        "raw_usd_value": 0.1,
        "usd_currency": "coins",
        "usd_currency_index": 5002,
        "items": {
            "Item 1": {
                "defindex": [
                    5002
                ],
                "prices": {
                    "6": {
                        "Tradable": {
                            "Craftable": [
                                {
                                    "value": 0.08,
                                    "currency": "usd",
                                    "difference": 0,
                                    "last_update": 1488385886,
                                    "value_high": 0.12
                                }
                            ]
                        }
                    }
                }
            },
            "Item 2": {
                "defindex": [
                    5021
                ],
                "prices": {
                    "6": {
                        "Tradable": {
                            "Craftable": [
                                {
                                    "value": 14,
                                    "currency": "usd",
                                    "difference": 14.11,
                                    "last_update": 1488385975,
                                    "value_high": 14.22
                                }
                            ]
                        }
                    }
                }
            }
        }
    }
}

Upvotes: 2

Views: 1621

Answers (2)

baao
baao

Reputation: 73241

I would use a promise's to do such tasks. This will make the order of tasks very clear, and you get easily readable code without many nested callbacks. In below example I'm using bluebird for the promises, but you can implement the "promisification" for yourself if you insist. Below will do what you want (checking for fs.existsSync is not needed, should the file not exist it will simply throw an error in fs.readFile which you can handle in catch.

Little sidenote: response.items.length returns undefined because items is an object in your case, which doesn't have a length property. I suppose you've mixed that with an array.

const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));
const fs = Promise.promisifyAll(require('fs'));
const url = 'http://localhost:3000';

request.getAsync(url)
  .then(data => fs.writeFileAsync("output.json", data.body))
  .then(() => fs.readFileAsync("output.json", "UTF-8"))
  .then(data => console.log(JSON.parse(data).response))
  .catch(err => console.log(err));

Here's a simple mock server that just returns the data you posted:

/* MOCK SERVER */
const http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify({
      "response": {
        "success": 1,
        "current_time": 1488743993,
        "raw_usd_value": 0.1,
        "usd_currency": "coins",
        "usd_currency_index": 5002,
        "items": {
          "Item 1": {
            "defindex": [
              5002
            ],
            "prices": {
              "6": {
                "Tradable": {
                  "Craftable": [
                    {
                      "value": 0.08,
                      "currency": "usd",
                      "difference": 0,
                      "last_update": 1488385886,
                      "value_high": 0.12
                    }
                  ]
                }
              }
            }
          },
          "Item 2": {
            "defindex": [
              5021
            ],
            "prices": {
              "6": {
                "Tradable": {
                  "Craftable": [
                    {
                      "value": 14,
                      "currency": "usd",
                      "difference": 14.11,
                      "last_update": 1488385975,
                      "value_high": 14.22
                    }
                  ]
                }
              }
            }
          }
        }
      }
    })
  );
}).listen(3000);

/* END MOCK */

Upvotes: 1

Ethan
Ethan

Reputation: 3798

You are writing the file asynchronously. This means that it will call fs.writeFile but then continue without waiting for it to finish. Because writing to the file system takes a [very small] amount of time, the program goes and calls the rest of the code while fs.writeFile is still going.

To fix this, simply put the rest of your code in the callback of fs.writeFile.

Hope that makes sense. See the fixed code below:

let request = require('request'),
  fs = require('fs'),
  DATA = require('./DATA.json'),
  url = "https://dataThatIAmTryingToGet";


request(url, (error, response, body) => {
  if (!error && response.statusCode === 200) {
    fs.writeFile("./DATA.json", (body), function () {
      if (fs.existsSync("./DATA.json")) {
        fs.readFile("./DATA.json", (err, data) => {
          if (err) {
            console.log("Whoopsiedaisy");
          } else {
            console.log("You did it nerd");
            console.log(DATA.response.items.length);
          }
        })
      }
    })
  } else {
    console.log("Got an error: ", error, ", status code: ", response.statusCode)
  }
});

Upvotes: 0

Related Questions