1

When I had a very simple file structure without routers and controllers in my node express project, I can easily read and return properly the contents of a json file, using fs-extra.

But when I added some folders to folders (and learned routers+controllers), I'm now having a hard time.

If I do this, by having a require variable (I utilize VSCode's autocompletion to make sure my file path is correct):

const fs = require("fs-extra")
const json = require("../../jsons/emojis.json")

exports.getEmojis = async (req, res) => {
  try {
    const emojis = await fs.readJson(json)
    const pretty = JSON.stringify(emojis, null, 4)
    res.setHeader("Content-Type", "application/json")
    res.send(pretty)
  } catch (err) {
    console.log("Error fs readJSON: " + err.message)
    res.status(500).send({
      message: "Error getting emojis."
    })
  }
}

I get an error:

Error fs readJSON: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Object


While if I put the string path directly to readJson like so:

const emojis = await fs.readJson("../../jsons/emojis.json")

I get an error:

Error fs readJSON: ENOENT: no such file or directory, open './emojis.json'


Edit: the file path is absolutely correct, like I mentioned I use VSCode.

emojis.json json file is under "jsons" folder, and that folder is 2 folders away from the controller file.

enter image description here

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
  • I think you should check the path then. look closely – 1baga Apr 26 '20 at 19:57
  • So, the error is apparently caused by `fs.readJson(json)`. That means that the `json` variable is what has the problem. That variable comes from `const json = require("../../jsons/emojis.json")` which probably means that `json` is an object, not a string and that is consistent with the error you get which tells you that `json` is an object. When you read JSON data with `require()`, you would typically get an object back. – jfriend00 Apr 26 '20 at 19:58

2 Answers2

4

This should solve it:

const path = require("path");
const fullPath = path.resolve("../../jsons/emojis.json");
const emojis = await fs.readJson(fullPath);
Punit Gupta
  • 3,808
  • 1
  • 18
  • 22
3

If you're trying to specify a path that is relative to your own controller file for something other than require(), then you have to manually combine the path the __dirname which is your module directory. So, if you're now trying to do this:

const emojis = await fs.readJson(fullPath);

You need to build fullPath to be relative to your own module directory:

const fullPath = path.join(__dirname, "../../jsons/emojis.json");
const emojis = await fs.readJson(fullPath);

Now, I can't see in your screen shot exactly where you're controller file is located in the directory hierarchy, so I'm not entirely sure that "../../jsons/emojis.json" is the right relative path to __dirname where your controller file is located, so you may need to adjust that. Or, you can show us the whole hierarchy, including where the controller file in question is located and we can advise more specifically.

But, the point here is that require() does some magic described here that looks relative to your module directory, but every other fs function just uses the current directory and that is set by how your overall app was launched, not where a given module is loaded. So, if you want to load something relative to your own module, you have to built the path manually using __dirname.

jfriend00
  • 683,504
  • 96
  • 985
  • 979