Lesson 23 — JSON Encoding với encoding/json
3 module dưới đây minh hoạ (1) tag struct ảnh hưởng output JSON ra sao,
(2) quá trình Unmarshal match field giữa JSON và struct,
(3) sự khác biệt RAM giữa ReadAll + Unmarshal (load-all)
và NewDecoder + Decode (stream) trên file 100MB.
1. Struct ↔ JSON — toggle tag, xem output live
Bên trái: struct Go với tag điều chỉnh được. Bên phải: JSON output do
json.Marshal sinh ra. Đổi tag / giá trị, output cập nhật tức thì.
omitempty chỉ bỏ field khi nó là zero value
của kiểu Go (vd "", 0, false, nil).
Với struct rỗng (vd time.Time{}) thì không — đây là pitfall phải dùng pointer.
2. Unmarshal flow — animate decode field-by-field
Chọn 1 trong các JSON input bên dưới, click "▶ Decode từng bước" để xem
json.Unmarshal match từng key với field của struct. Field khớp →
xanh; field struct thiếu trong JSON → đỏ; key JSON không có field tương ứng → cam.
dec.DisallowUnknownFields() thì case "JSON dư" sẽ trả lỗi.
3. Stream vs Load-all — RAM khi parse file 100MB
Giả lập đọc file NDJSON 100MB (1 triệu user JSON). So sánh 2 cách:
Load-all (io.ReadAll + json.Unmarshal) — toàn bộ file vào RAM
trước khi parse; vs Stream (json.NewDecoder.Decode) — đọc nhỏ giọt,
chỉ giữ 1 object tại 1 thời điểm.
❌ Load-all: ReadAll + Unmarshal
✅ Stream: NewDecoder.Decode
json.NewDecoder(r.Body).Decode(&req), không phải
io.ReadAll(r.Body) trước.