Go มันก็แปลง JSON ง่ายนิดเดียว! (ถ้าไม่เผลอพลาด)
สวัสดีครับ! วันนี้ผมอยากเล่าเรื่องการทำงานกับ JSON ใน Go (Golang) ให้ฟัง. แรกๆ ที่ผมเริ่มเขียน Go เนี่ย ยอมรับเลยว่าแอบ งง นิดๆ กับเรื่อง struct กับ tag ว่ามันจะแปลงเป็น JSON ได้ไงฟะ? แต่พอเข้าใจคอนเซ็ปต์แล้วมันก็โคตร ง่ายเลยนะ
พื้นฐานก่อน Go เนี่ย มันมี encoding/json มาให้ในตัวเลย ไม่ต้อง ลง package เพิ่มให้วุ่นวาย. เวลาเราจะแปลง struct เป็น JSON (Marshal) หรือแปลง JSON กลับมาเป็น struct (Unmarshal) เนี่ย มันใช้สองฟังก์ชันนี้แหละ
สมมติเรามี struct ง่ายๆ แบบนี้:
package main
import "fmt"
import "encoding/json"
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"` // omitempty คือถ้าค่าว่าง (zero value) จะไม่เอาเข้า JSON
IsActive bool `json:"is_active"`
CreatedAt string `json:"created_at"`
}
func main() {
// สร้าง User object
u := User{
ID: 1,
Name: "บักหำน้อย",
Email: "[email protected]",
IsActive: true,
CreatedAt: "2023-10-27T10:00:00Z",
}
// Marshal (แปลง struct เป็น JSON)
jsonData, err := json.Marshal(u)
if err != nil {
fmt.Println("Error marshalling JSON:", err)
return
}
fmt.Println("JSON จาก Struct:")
fmt.Println(string(jsonData))
fmt.Println("\n---")
// Unmarshal (แปลง JSON กลับมาเป็น struct)
jsonString := `{"id":2,"name":"เจ๊แต๋ว","email":"[email protected]","is_active":false,"created_at":"2023-10-27T11:00:00Z"}`
var newUser User
err = json.Unmarshal([]byte(jsonString), &newUser)
if err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return
}
fmt.Println("Struct จาก JSON:")
fmt.Printf("ID: %d, Name: %s, Email: %s, IsActive: %t\n", newUser.ID, newUser.Name, newUser.Email, newUser.IsActive)
}
รันโค้ดบนจะเห็นผลลัพธ์ประมาณนี้:
JSON จาก Struct:
{"id":1,"name":"บักหำน้อย","email":"[email protected]","is_active":true,"created_at":"2023-10-27T10:00:00Z"}
---
Struct จาก JSON:
ID: 2, Name: เจ๊แต๋ว, Email: [email protected], IsActive: false
สิ่งที่ผมเคยเจอตอนทำโปรเจกต์ (Error เล็กๆ แต่โคตรน่าหงุดหงิด) อันนี้จริงๆ มันไม่ใช่ Error แบบโปรแกรมพัง แต่มันคือ "Data ไม่มาตามที่คิด" นั่นแหละ สมมติคุณได้รับ JSON มาแบบนี้ (จาก API ปลายทางอะไรก็ได้):
{
"userId": 123,
"userName": "Boss",
"isActive": "true" <-- ตรงนี้แหละตัวดี
}
แล้วเราดันไปประกาศ struct แบบนี้:
type APIResponse struct {
UserID int `json:"userId"`
UserName string `json:"userName"`
IsActive bool `json:"isActive"` // หวังว่าจะได้ bool ใช่ไหม?
}
พอคุณเอาไป json.Unmarshal ปุ๊บ โอกาสที่คุณจะเจอ false ใน IsActive ทั้งที่ใน JSON มันเป็น "true" สูงมาก หรือบางทีก็ Error ไปเลย เพราะ Go มันคาดหวัง bool (true/false) จริงๆ ไม่ใช่ string "true"/"false"
ตัวอย่าง Error ที่เจอ: ถ้าเราลองทำแบบนี้
package main
import (
"encoding/json"
"fmt"
)
type BadUser struct {
ID int `json:"id"`
IsActive bool `json:"is_active"`
}
func main() {
badJsonString := `{"id":1,"is_active":"true"}` // is_active เป็น string แทนที่จะเป็น bool
var badUser BadUser
err := json.Unmarshal([]byte(badJsonString), &badUser)
if err != nil {
fmt.Println("เฮ้ย! เกิด Error ตอน Unmarshal:", err)
// Error ที่เจอจริงจะประมาณนี้:
// เฮ้ย! เกิด Error ตอน Unmarshal: json: cannot unmarshal string into Go struct field BadUser.is_active of type bool
return
}
fmt.Printf("BadUser: %+v\n", badUser)
}
เห็นไหม! มันจะฟ้องเลยว่า "cannot unmarshal string into Go struct field ... of type bool" วิธีแก้ก็คือ ต้องไปดู type ใน JSON ที่ได้รับมาดีๆ ว่ามันเป็น string หรือ bool หรือ int กันแน่. ถ้ามันไม่ตรง ก็ต้องปรับ struct เราให้ตรง หรือ ไม่ก็ต้องเขียน Custom Unmarshaler ซึ่งอันนั้นมันจะแอดวานซ์ไปหน่อย. สำหรับมือใหม่แค่รู้ว่ามันเกิดแบบนี้ได้ก็พอละ
สรุปแล้ว การจัดการ JSON ใน Go ไม่ได้ยากอย่างที่คิด แค่ต้องระวังเรื่อง type mismatch ให้ดีๆ ครับ. ถ้าติดตรงไหนลองพิมพ์ดู error ที่เจอแล้ว Search Google ดู ส่วนใหญ่จะมีคนเจอเหมือนๆ กันเยอะแยะ! โชคดีครับ!