The whole shelf in one go — JSON to a file
How do you turn a []Item into file content? We could write it line by line, but there is something better: JSON — a text format understood by Go, by humans, and by nearly every other language.
The encoding/json package turns the whole shelf into text with one call:
data, err := json.MarshalIndent(items, "", " ")
And at the end of a struct field you can add a tag — it sets the key name in the file:
type Item struct {
Title string `json:"title"`
Pages int `json:"pages"`
}
The file will look like this — open it and read, it is just text:
[
{
"title": "Dune",
"pages": 412
}
]
For writing and reading we use the high-level pair — it opens AND closes the file itself (step 1's "open–use–close" handled for you):
err := os.WriteFile("items.json", data, 0o644) // writes the whole file
data, err := os.ReadFile("items.json") // reads the whole file
One design detail remains — the most important idea of this lesson: on the very first run the file does NOT exist yet. That is not an error, it is a normal situation, and it gets its own branch:
data, err := os.ReadFile(saveFile)
if errors.Is(err, fs.ErrNotExist) {
return []Item{}, nil // first run — just an empty shelf
}
errors.Is separates "file missing" (normal → empty list) from every other trouble (a real error → return err). An app that crashes on its first run because it "could not find its own file" is an app nobody runs a second time.
Tip. This
saveItems+loadItemsdesign is not just an exercise: it is exactly the storage layer you will use in the final project. Build it well now — in the finale you simply bring it along.