كيفية تحويل Go struct إلى JSON: من المبتدئ إلى المحترف
العمل مع JSON هو أمر أساسي لأي مطور خلفية (backend) بلغة Go. كل يوم تقريبًا، تحتاج إلى إرسال بيانات إلى العميل، أو استقبال طلبات من API، أو حفظ الإعدادات. وفي 90% من الحالات، يكون هذا JSON. ولكن كيف يمكن تحويل struct الخاص بك إلى JSON قابل للقراءة بشكل صحيح؟ قد يبدو الأمر بسيطًا! لكن الشيطان يكمن في التفاصيل: وسوم غير صحيحة، حقول فارغة، أخطاء منسية - وفجأة يعيد API الخاص بك شيئًا غير متوقع.
في هذه المقالة، سنشرح تحويل Go struct إلى JSON من الأساسيات إلى التقنيات المتقدمة. ستتعلم كيفية عمل الوسوم، وكيفية إخفاء الحقول الفارغة، وكيفية تسلسل الهياكل المتداخلة، وكيفية تجنب الأخطاء. هيا بنا!
الأساسيات: حزمة encoding/json
في المكتبة القياسية للغة Go، توجد حزمة قوية تسمى encoding/json. أدواتها الرئيسية هي الدالتان json.Marshal (لتحويل struct إلى JSON) و json.Unmarshal (للعملية العكسية).
لنلقِ نظرة على مثال أساسي. لدينا هيكل مستخدم:
package main
import ( "encoding/json" "fmt")
type User struct { Name string Age int Email string}
func main() { user := User{ Name: "أليكسي", Age: 30, Email: "alex@example.com", }
jsonData, err := json.Marshal(user) if err != nil { fmt.Println("خطأ:", err) return }
fmt.Println(string(jsonData)) // الإخراج: {"Name":"أليكسي","Age":30,"Email":"alex@example.com"}}كل شيء يعمل، ولكن هناك نقطة: المفاتيح في JSON تطابق أسماء الحقول في الهيكل (بحرف كبير). وهذا لا يتوافق مع معايير JSON (عادةً ما يُستخدم camelCase أو snake_case).
وسوم JSON: التحكم في أسماء المفاتيح
للتحكم في كيفية ظهور الحقول في JSON، نستخدم وسوم الهيكل (struct tags). وهي تعليقات توضيحية خاصة تُكتب بعد نوع الحقل بين علامتي اقتباس خلفيتين (backticks).
type User struct { Name string `json:"name"` Age int `json:"age"` Email string `json:"email"`}
// الآن سيكون الإخراج:// {"name":"أليكسي","age":30,"email":"alex@example.com"}تحل الوسوم عدة مشاكل في وقت واحد:
- تغيير اسم الحقل — تجعل المفاتيح جميلة وقابلة للقراءة
- تخطي الحقل — باستخدام
json:"-"يتم استبعاد الحقل تمامًا من JSON - التحكم في الحقول الفارغة — الخيار
omitemptyيخفي الحقل إذا كان يحتوي على قيمة صفرية
مثال عملي مع omitempty
type User struct { Name string `json:"name"` Age int `json:"age,omitempty"` Email string `json:"email,omitempty"` IsAdmin bool `json:"is_admin,omitempty"`}
func main() { user := User{Name: "ماريا"} jsonData, _ := json.Marshal(user) fmt.Println(string(jsonData)) // الإخراج: {"name":"ماريا"} // تم تخطي Age و Email و IsAdmin لأنها فارغة}لاحظ: omitempty يعمل مع القيم الصفرية — 0، false، سلسلة فارغة، nil. هذا مريح جدًا لـ API حيث لا تحتاج إلى إضافة حقول غير ضرورية.
الهياكل المتداخلة والمصفوفات (Slices)
في المشاريع الحقيقية، نادرًا ما تكون البيانات مسطحة. غالبًا ما يكون لديك كائنات متداخلة أو مصفوفات. تتعامل Go مع هذا بشكل ممتاز — حزمة json تعالج جميع الحقول بشكل تكراري.
type Address struct { City string `json:"city"` Street string `json:"street"` ZipCode string `json:"zip_code"`}
type Company struct { Name string `json:"name"` Address Address `json:"address"` Tags []string `json:"tags"`}
func main() { company := Company{