Json Marshal Unmarshal
Fast recall
Quick revision
Core answer
Whether you understand Json Marshal Unmarshal beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The round-trip, executed:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age,omitempty"` // skip when 0
}
// Marshal: Go → JSON
u := User{Name: "Al", Email: "al@x.com"}
b, _ := json.Marshal(u)
// {"name":"Al","email":"al@x.com"} — Age omitted (omitempty, zero value) — verified
// Unmarshal: JSON → Go
var parsed User
json.Unmarshal(b, &parsed)
// parsed.Name == "Al", parsed.Email == "al@x.com" — verifiedThe struct tag is the name mapping: json:"name" says 'this Go field serializes as the JSON key "name".' Without a tag, the Go field name is used as-is. The options: omitempty (skip zero values), - (never serialize), json:"name,string" (encode as a JSON string even for numbers).
The streaming alternatives for large data: json.NewDecoder(reader).Decode(&v) (parse from a stream — HTTP bodies, files) and json.NewEncoder(writer).Encode(v) (write to a stream — HTTP responses). The batch forms (Marshal/Unmarshal) work on complete []byte — fine for everything that fits in memory.
The error cases every handler must handle: syntax error (bad JSON — not json → error, verified) and type mismatch (JSON string into Go int → error, verified). Both are the CLIENT's fault — 400 in an HTTP context, never 500.
Json Marshal Unmarshal
Direct Answer
Marshal: b, err := json.Marshal(v) — struct→[]byte. Unmarshal: err := json.Unmarshal(b, &v) — []byte→struct. Field names via struct tags: json:"name". Decoder/Encoder for streams.
Deep Dive & Architecture
The reflection machinery: encoding/json uses reflection over the struct's fields at runtime — reading the tags, matching JSON keys to Go fields (case-insensitive fallback), building the encoder/decoder per type. The cost: reflection is ~10-100x slower than a hand-written converter — the price of the universal 'any struct, any JSON, zero codegen.' For hot paths, the alternatives (easyjson codegen, json-iterator) exist; for 95% of services, the reflection cost is noise.
The field-matching subtleties: unmarshal matches JSON keys to Go fields case-insensitively when there's no exact tag match — {"Name":...} fills the Name field even with the json:"name" tag (the tag's key match is exact; the fallback is case-insensitive). Unexported fields are never serialized (the notes string field in our demo — invisible to JSON). Unmatched JSON keys are silently dropped — strictness requires DisallowUnknownFields (the Decoder option) when the contract needs enforcing.
The omitempty's semantics, precisely: it omits when the value is the TYPE'S ZERO — 0, "", nil, false, empty slice/map, nil pointer. It cannot express 'omit when the value is semantically empty-but-nonzero' (0 is a valid age; omitempty hides it). For that: pointer fields (*int — nil is omitted, *int(0) is included) or custom marshaling (MarshalJSON on the type). The pointer trick is the standard answer for '0 is a legitimate value.'
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- When would you use Json Marshal Unmarshal in a real project?
- How would you compare Json Marshal Unmarshal with an alternative?
- What is a common mistake when using Json Marshal Unmarshal?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.