Files and paths

Build a notes command-line program

Combine arguments, JSON parsing, paths, and promise-based filesystem calls in one small Node.js program.

8 minute lesson

~~~

Build a program with add, list, and remove commands.

Define the command contract before the storage code:

node notes.js add "Buy milk"
node notes.js list
node notes.js remove <id>

Parse only the arguments each command accepts. Missing text, an invalid ID, or an unknown command is a user error: print a short usage message to standard error and set a non-zero exit status.

Store notes in a JSON file beside the ES module, not wherever the user happened to launch it:

const dataUrl = new URL('./notes.json', import.meta.url)

Treat only a missing file as an empty collection:

async function readNotes() {
  try {
    return JSON.parse(await readFile(dataUrl, 'utf8'))
  } catch (error) {
    if (error.code === 'ENOENT') return []
    throw error
  }
}

Invalid JSON, permission errors, and I/O failures must remain visible. Silently replacing corrupt storage with [] could make the next write erase recoverable notes.

Write a complete new snapshot to a temporary file beside the destination, flush and close it as required by your durability needs, then rename it over notes.json. Renaming on the same filesystem prevents readers from observing a half-written JSON document. Clean up a leftover temporary file after a failed write.

Atomic replacement is not the same as concurrency control. Two CLI processes can both read the old list and then each rename a different update; the last rename wins. Either document that only one process may modify the file, add an appropriate lock, or use a database when concurrent writers are a requirement.

Keep the command flow explicit:

  1. parse and validate the command
  2. load and validate the stored array
  3. calculate the new array without mutating partial state
  4. persist it safely
  5. print the result only after persistence succeeds

Use stable generated IDs rather than array indexes, because removing one note changes later indexes.

Return a non-zero exit status for an unknown command or invalid input.

Your action is to implement all three commands, then test a missing file, malformed JSON, invalid ID, failed write, and two simultaneous add commands. Document which concurrency guarantee your version actually provides.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →