JSON and encoding/json
Fundamentals Chapter 10 used response.json() in JavaScript without much ceremony — JSON parses directly into a plain object there, since JavaScript objects and JSON already share the same shape. Go's static typing (Fundamentals Chapter 2) means converting to and from JSON needs an explicit step: marshaling (struct → JSON) and unmarshaling (JSON → struct), both handled by the standard library's encoding/json package.
Marshaling — Struct to JSON
json.Marshal returns the JSON as a []byte slice, plus an error — the same Fundamentals Chapter 5 pattern used throughout the language. string(data) converts those raw bytes into a printable string. Note that Name and Age appear capitalised in the JSON output by default — only capitalised (exported) struct fields are visible to encoding/json at all.
Struct Tags — Controlling the JSON Output
The backtick-delimited text after each field is a struct tag — metadata read by encoding/json at runtime. json:"name" renames the field for JSON purposes (lowercase, matching typical API conventions); omitempty drops the field entirely from the output when it holds its zero value (Fundamentals Chapter 2) — here, Email disappears since it was never set.
data, _ := json.Marshal(p) uses the blank identifier (Fundamentals Chapter 4) to explicitly throw away the error return value — acceptable in a quick example, but real code should always check it properly, the same way err != nil is checked everywhere else in Go.
Unmarshaling — JSON to Struct
json.Unmarshal goes the other direction: raw JSON bytes into a struct. The destination is passed as a pointer (&p) — exactly Intermediate Chapter 1's pointer-receiver lesson applied here: without the &, Unmarshal would only be able to fill in a throwaway copy, and p back in the caller would remain empty.
json.Unmarshal(jsonData, p) (no &) compiles and runs without panicking in many cases, but p never actually gets populated — Unmarshal needs a pointer specifically so it can write through to the real variable, the same plain-vs-pointer-receiver distinction from Intermediate Chapter 1.
Fetching JSON from a Real API
This is the complete realistic pattern: http.Get fetches the response, io.ReadAll reads its full body into bytes, json.Unmarshal parses those bytes into a struct. defer resp.Body.Close() (Intermediate Chapter 3's defer) guarantees the response body is closed once the function returns, success or failure — the direct Go equivalent of JavaScript Fundamentals Chapter 10's fetch + response.json() pair.
| JavaScript | Go |
|---|---|
| JSON.stringify(obj) | json.Marshal(value) |
| JSON.parse(text) | json.Unmarshal(bytes, &target) |
| No equivalent — keys match property names | `json:"key"` struct tag controls the JSON key name |
| await response.json() | io.ReadAll(resp.Body) + json.Unmarshal(body, &target) |
Coding Challenges
Define a struct Product with fields Name (string), Price (float64), and InStock (bool), with json tags using lowercase key names. Create one, marshal it with json.Marshal, and print the resulting JSON string.
📄 View solutionGiven a raw JSON string `{"name":"Laptop","price":999.99,"inStock":true}`, define a matching struct with appropriate json tags, unmarshal it, and print each field.
📄 View solutionWrite a function fetchUser(id int) (User, error) that fetches from https://jsonplaceholder.typicode.com/users/{id}, unmarshals into a User struct with at least Name and Email fields (with json tags), properly closing the response body with defer. Call it and print the result, handling any error.
📄 View solutionChapter 5 Quick Reference
- json.Marshal(value) — struct/value → JSON []byte, plus an error
- json.Unmarshal(bytes, &target) — JSON []byte → struct; target MUST be a pointer
- Only capitalised (exported) struct fields are visible to encoding/json
- `json:"key"` — struct tag controlling the JSON field name
- `json:"key,omitempty"` — omits the field from output if it's the zero value
- http.Get(url) + io.ReadAll(resp.Body) + json.Unmarshal — the full fetch-and-parse pattern
- defer resp.Body.Close() — always close a response body once done with it
- This completes Go Advanced (Course 3) and the Go course overall as currently planned across all 3 courses.