Go encoding/json/v2: واجهة JSON جديدة مستقرة في Go 1.27

encoding/json/v2 و jsontext بقوا مستقرين في Go 1.27: سلوك أدق افتراضيًا، Unmarshal أسرع لحد 10x، و v1 لسه مدعوم.

يوم 4 نوفمبر 2026 فريق Go نشر على المدونة الرسمية إن encoding/json/v2 و encoding/json/jsontext بقوا مستقرين ومتاحين بشكل عام في Go 1.27. ده مش تجريب تاني — التجربة بدأت رسميًا في Go 1.25، والنهاردة الحزم دي دخلت المكتبة القياسية كـ GA.

ليه احتاجوا v2 أصلًا؟

encoding/json (اللي هنسميه v1) موجود من قبل Go 1.0 واشتغل كويس سنين طويلة. بس مع الوقت ظهرت مشاكل صعب تتصلح جوه نفس الـ API من غير ما يكسروا Compatibility Promise:

  • قبول UTF-8 غلط (مع إن RFC 8259 بيطلب UTF-8 صحيح)
  • قبول أسماء مكررة جوه نفس الـ object (وده اتستغل قبل كده في ثغرات زي CVE-2017-12635)
  • الـ nil slice و الـ nil map بيتكتبوا null، وده بيسبب أخطاء مع أنظمة تانية متستناش null لمصفوفة أو object
  • مطابقة أسماء الحقول case-insensitive وقت الـ unmarshal
  • خيارات على Encoder/Decoder مش وصلة لـ Marshal/Unmarshal، ومفيش streaming حقيقي

المحاولة إنهم يصلحوا v1 مباشرة اتصطدمت بوعد التوافق. فالحل كان namespace جديد: encoding/json/v2.

طبقتين: jsontext و json/v2

الفريق فصل الشغل لتين:

  • encoding/json/jsontext: النحو فقط (syntax) — Encoder و Decoder بيشتغلوا streaming حقيقي على tokens و values من غير reflection
  • encoding/json/v2: المعاني (semantics) — العلاقة بين قيم JSON وقيم Go، فوق jsontext

الـ API الأساسي لـ v2 مألوف:

json.Marshal(in any, opts ...Options) ([]byte, error)
json.MarshalWrite(out io.Writer, in any, opts ...Options) error
json.Unmarshal(in []byte, out any, opts ...Options) error
json.UnmarshalRead(in io.Reader, out any, opts ...Options) error

والجديد المهم للـ performance: واجهات streaming MarshalerTo و UnmarshalerFrom اللي بتشتغل على jsontext.Encoder / Decoder بدل ما ترجع []byte كامل وتعيد parse.

إيه اللي اتغيّر في السلوك؟

أهم الفروقات الافتراضية في v2 (حسب المقال الرسمي):

  • خطأ عند UTF-8 غير صالح
  • خطأ لو الـ object فيه اسم مكرر
  • الـ nil slice → مصفوفة فاضية، والـ nil map → object فاضي
  • مطابقة أسماء الحقول case-sensitive
  • omitempty اتأعيد تعريفه: يتجاهل الحقل لو هيطلع قيمة JSON فاضية (null أو "" أو [] أو {})
  • time.Duration مفيش تمثيل افتراضي — بيطلع error إلا لو حددت options

ومعظم الفروقات دي ليها option أو struct tag ترجعك لسلوك v1 لو محتاج.

الأداء والهجرة

حسب بنشماركات الفريق: Marshal تقريبًا زي v1 (ساعات أسرع شوية وساعات أبطأ)، أما Unmarshal أسرع بشكل واضح — لحد 10x في بعض الحالات. وفي Go 1.28 متوقع تحسينات إضافية في الحالات اللي v2 لسه فيها أبطأ من v1.

حاجة مهمة جدًا للـ ecosystem: v1 لسه مدعوم للأبد، ومش لازم تهاجر. وكمان تحت الغطا v1 بقى مبني على v2 بخيارات توافق — يعني packages بتستخدم v1 و v2 تقدر تشتغل مع بعض، و MarshalJSON القديمة لسه شغالة مع v2، و MarshalJSONTo الجديدة بتشتغل كمان من خلال v1.

لو عايز تهاجر تدريجي، تقدر تختار كل سلوك v2 ماعدا نقطة واحدة، أو العكس — زي السماح بالأسماء المكررة مع باقي سلوك v2.

رأيي

الـ JSON في Go كان محتاج تحديث من سنين، والفريق خد وقته (~6 سنين من أواخر 2020). المهم مش إنهم «بدّلوا الاسم» — المهم إن السلوك الافتراضي بقى أقرب للمعايير والأأمن، والـ Unmarshal بقى أسرع بشكل محسوس، والهجرة مش إجبار. لو بتكتب خدمة بتتعامل مع JSON كتير، جرّب v2 على مسار unmarshal تقيل وقِس قبل ما تنقل الـ production كله.

المصادر

  • Go Blog — A new Go API for JSON: https://go.dev/blog/jsonv2
  • Package encoding/json/v2 (docs عبر go.dev)
  • Package encoding/json/jsontext
  • Go
  • Golang
  • JSON
  • Backend
  • OpenSource
  • encoding