Reputation: 800
I start with an empty file cart.json (just touch cart.json
)
I have a default state for the file contents in my mind:
const defaultCart = {
products: [], // Array<{ id: string; quantity: number; }>
totalPrice: 0
}
Now, when I read the contents for the very first time (remember the file has no content):
const fs = require('fs');
exports.readCartDataFromFile = (cb) => {
fs.readFile(filePath, (error, fileData) => {
const cart = {...defaultCart};
if (!error) {
const parsedFileData = JSON.parse(fileData); // throws error
console.log('parsedFileData: ', parsedFileData);
/* Do something with the parsedFileData */
}
cb(cart);
});
}
I see this error:
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at /Users/someusername/nodejs/main-app-altered/models/Cart.js:18:41
at FSReqCallback.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:73:3)
[nodemon] app crashed - waiting for file changes before starting...
The temporary solution is that I start the file cart.json with the defaultCart state so that I never come across this error.
But, my question is - Is there a way I could have determined (via some util in code) that the file has no contents so while initializing the model in the constructor, I write the defaultCart state into the file using fs.writeFile?
Upvotes: 2
Views: 1436
Reputation: 74307
Doesn't seem like it should be much more complicated than this:
const fs = require('fs');
const defaultCart = JSON.stringify({
products: [], // Array<{ id: string; quantity: number; }>
totalPrice: 0
});
exports.readCartDataFromFile = (cb) => {
fs.readFile( filePath, 'utf8', (e, s) => {
let err = e;
let cart;
if (!err) {
try {
const json = s.trim().length > 0 ? s : defaultCart ;
cart = JSON.parse(json);
} catch (error) {
err = error;
}
}
cb(err, cart);
});
}
But if you want to create/initialize the file with default contents, then something like this would work:
const fs = require('fs/promises');
async function ensureInitialized(filePath) {
const fileInfo = await fs.stat( filePath ).catch(() => undefined);
let initialized = fileInfo && fileInfo.size > 0;
if ( !initialized ) {
// if the file doesn't exist, or has a size of zero,
// create/overwrite the default JSON to the file
await fs.writeFile( filePath, defaultCart, {
encoding: 'utf8',
mode: 0o644,
flag: 'w'
});
initialized = true;
}
return initialized;
}
const defaultCart = JSON.stringify({
products: [],
totalPrice: 0
});
Upvotes: 1
Reputation: 115970
If you want to test for an empty fileData
Buffer inside your read callback, you can just do
if(fileData.length == 0) { ... }
Or, if you want to catch any invalid JSON (including empty strings), you could nest your parse
into a try
:
try {
const parsedFileData = JSON.parse(fileData);
// ...
} catch(e) {
console.err("Invalid JSON inside cart data file: ", e)
}
Upvotes: 3