JSONTech

JSON Schema: What It Is and How to Use It

Learn JSON Schema from scratch. Understand types, constraints, composition keywords, $ref, and see a complete practical example for API validation.

فريق JSONTechFebruary 1, 202511 min read

ما هو مخطط JSON؟

مخطط JSON هو مفردات تتيح لك وصف هيكل بيانات JSON. فكر في الأمر على أنه عقد: يحدد الحقول التي يجب أن يحتوي عليها مستند JSON، وأنواع تلك الحقول، والقيود التي يجب أن تلبيها. عندما يتوافق مستند مع مخططه، فإنه صالح. عندما لا يتوافق، يخبرك المدقق بالضبط ما الخطأ الذي حدث.

هذا مهم لأن JSON نفسه مرن من الناحية الهيكلية. لا يمنع أي شيء في مواصفة JSON واجهة برمجة التطبيقات من إرجاع سلسلة حيث تتوقع رقمًا، أو من حذف حقل مطلوب. يغلق مخطط JSON هذه الفجوة.

لماذا يعتبر مخطط JSON مهمًا

  • عقود واجهة برمجة التطبيقات. حدد بالضبط ما تتوقعه واجهة برمجة التطبيقات الخاصة بك وما تعيده. يمكن لكل من فرق العميل والخادم التحقق من صحة الحمولة بشكل مستقل.
  • التحقق من صحة البيانات. اكتشف البيانات غير الصحيحة عند الحدود - في تقديم النماذج، أو حمولة الويب هوك، أو ملفات التكوين، أو كتابة البيانات في قاعدة البيانات.
  • التوثيق. المخطط هو توثيق يمكن قراءته آليًا. يمكن للأدوات إنشاء مستندات قابلة للقراءة من قبل البشر، ونماذج، وحتى بيانات وهمية منها.
  • توليد الكود. توليد واجهات TypeScript، أو هياكل Go، أو فئات بيانات Python مباشرة من مخططك.

الأساسيات: النوع، الخصائص، المطلوبة

يبدأ كل مخطط JSON بـ type. هذا يخبر المدقق بنوع القيمة المتوقع في المستوى الأعلى:

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "الاسم الكامل للمستخدم"
    },
    "age": {
      "type": "integer",
      "description": "العمر بالسنوات"
    }
  },
  "required": ["name"]
}

يقول هذا المخطط: "أتوقع كائن JSON مع خاصية name (سلسلة، مطلوبة) وخاصية age اختيارية (عدد صحيح)." أي كائن يفتقر إلى name أو يقدم name غير سلسلة يكون غير صالح.

جميع أنواع مخطط JSON

يدعم مخطط JSON سبعة أنواع بدائية. إليك كل واحد مع مثال مخطط بسيط:

النوعالقيم الصالحةمثال المخطط
string"hello", ""{"type": "string"}
number3.14, -1, 0{"type": "number"}
integer42, -7{"type": "integer"}
booleantrue, false{"type": "boolean"}
nullnull{"type": "null"}
object{"key": "value"}{"type": "object", "properties": {...}}
array[1, 2, 3]{"type": "array", "items": {...}}

الكائنات بالتفصيل

استخدم properties لتعريف الحقول المتوقعة، وrequired لإدراج الحقول الإلزامية، وadditionalProperties للتحكم فيما إذا كانت الحقول الإضافية مسموح بها:

{
  "type": "object",
  "properties": {
    "id": { "type": "integer" },
    "email": { "type": "string", "format": "email" }
  },
  "required": ["id", "email"],
  "additionalProperties": false
}

تعيين additionalProperties: false يرفض أي كائن يحتوي على مفاتيح غير مدرجة في properties. هذا مفيد لعقود واجهة برمجة التطبيقات الصارمة.

المصفوفات بالتفصيل

استخدم items لتعريف شكل كل عنصر، وminItems / maxItems لتقييد الطول:

{
  "type": "array",
  "items": { "type": "string" },
  "minItems": 1,
  "maxItems": 10,
  "uniqueItems": true
}

هذا يقبل مصفوفة من 1 إلى 10 سلاسل فريدة. ستفشل مصفوفة فارغة أو مصفوفة تحتوي على عناصر مكررة في التحقق من الصحة.

القيود وكلمات التحقق من الصحة

بجانب الأنواع الأساسية، يوفر مخطط JSON قيودًا دقيقة لكل نوع:

قيود السلاسل

الكلمة الرئيسيةالوصفالمثال
minLengthالحد الأدنى لعدد الأحرف"minLength": 1
maxLengthالحد الأقصى لعدد الأحرف"maxLength": 255
patternتعبير عادي يجب أن تتطابق معه السلسلة"pattern": "^[A-Z]{2}\\\\d{4}$"
formatتلميح تنسيق دلالي"format": "email"
enumالقيم المسموح بها"enum": ["active", "inactive"]

قيود الأرقام

الكلمة الرئيسيةالوصفالمثال
minimumيجب أن تكون القيمة >= هذا"minimum": 0
maximumيجب أن تكون القيمة <= هذا"maximum": 100
exclusiveMinimumيجب أن تكون القيمة > هذا"exclusiveMinimum": 0
exclusiveMaximumيجب أن تكون القيمة < هذا"exclusiveMaximum": 1000
multipleOfيجب أن تكون القيمة قابلة للقسمة على هذا"multipleOf": 0.01

دمج المخططات: allOf، anyOf، oneOf، not

تتيح لك كلمات التركيب بناء مخططات معقدة من مخططات أبسط:

  • allOf — يجب أن تكون البيانات صالحة ضد جميع المخططات المدرجة. تستخدم لدمج قيود متعددة أو توسيع مخطط أساسي.
  • anyOf — يجب أن تكون البيانات صالحة ضد واحد على الأقل من المخططات المدرجة. مفيد للحقول التي تقبل تنسيقات متعددة.
  • oneOf — يجب أن تكون البيانات صالحة ضد واحد فقط من المخططات المدرجة. جيد للاتحادات المميزة.
  • not — يجب أن تكون البيانات غير صالحة ضد المخطط المعطى.
{
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "type": { "const": "email" },
        "address": { "type": "string", "format": "email" }
      },
      "required": ["type", "address"]
    },
    {
      "type": "object",
      "properties": {
        "type": { "const": "phone" },
        "number": { "type": "string", "pattern": "^\\\\+?[0-9]{7,15}$" }
      },
      "required": ["type", "number"]
    }
  ]
}

هذا المخطط يقبل إما جهة اتصال عبر البريد الإلكتروني أو جهة اتصال عبر الهاتف، ولكن ليس كلاهما - طريقة نظيفة لنمذجة الاتحادات المميزة.

القابلية لإعادة الاستخدام مع $ref

تتكرر المخططات بسرعة. تتيح لك الكلمة الرئيسية $ref الإشارة إلى تعريف قابل لإعادة الاستخدام:

{
  "type": "object",
  "properties": {
    "billing_address": { "$ref": "#/$defs/address" },
    "shipping_address": { "$ref": "#/$defs/address" }
  },
  "$defs": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" },
        "zip": { "type": "string", "pattern": "^[0-9]{5}(-[0-9]{4})?$" }
      },
      "required": ["street", "city", "zip"]
    }
  }
}

كل من billing_address و shipping_address تشترك في نفس الهيكل دون تكرار. قسم $defs (يسمى definitions في المسودات القديمة) هو المكان التقليدي لتخزين المخططات القابلة لإعادة الاستخدام.

مثال كامل: التحقق من صحة تسجيل المستخدم

إليك مخطط في العالم الحقيقي للتحقق من صحة حمولة تسجيل المستخدم. يستخدم معظم الميزات التي قمنا بتغطيتها:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "UserRegistration",
  "description": "مخطط لنقطة النهاية POST /api/register",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "minLength": 3,
      "maxLength": 30,
      "pattern": "^[a-zA-Z0-9_]+$",
      "description": "اسم مستخدم أبجدي رقمي، من 3 إلى 30 حرفًا"
    },
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 254
    },
    "password": {
      "type": "string",
      "minLength": 8,
      "maxLength": 128,
      "description": "على الأقل 8 أحرف"
    },
    "age": {
      "type": "integer",
      "minimum": 13,
      "maximum": 150
    },
    "role": {
      "type": "string",
      "enum": ["user", "moderator"],
      "default": "user"
    },
    "acceptedTerms": {
      "type": "boolean",
      "const": true
    },
    "tags": {
      "type": "array",
      "items": { "type": "string", "maxLength": 20 },
      "maxItems": 5,
      "uniqueItems": true
    }
  },
  "required": ["username", "email", "password", "acceptedTerms"],
  "additionalProperties": false
}

لاحظ كيف تحتوي كل حقل على قيود واضحة وقابلة للتنفيذ. سيرفض المدقق اسم مستخدم مكون من حرفين، أو عمر أقل من 13، أو علامات مكررة، أو أي حقول إضافية غير مدرجة في المخطط.

جرب بنفسك: ألصق أي JSON وقم بإنشاء مخطط تلقائيًا باستخدام مولد مخطط JSON.

مخطط JSON في العالم الحقيقي

OpenAPI / Swagger

تستخدم OpenAPI مخطط JSON (مع بعض التوسعات) لتعريف أجسام الطلب، وأشكال الاستجابة، ومعلمات الاستعلام. كل كتلة schema في مواصفة OpenAPI هي مخطط JSON. إذا كنت تكتب مستندات OpenAPI، فأنت بالفعل تكتب مخطط JSON.

التحقق من صحة النموذج

تستخدم مكتبات مثل react-jsonschema-form و ajv (أسرع مدقق لمخطط JSON لجافا سكريبت) المخططات لإنشاء والتحقق من صحة النماذج في وقت التشغيل. حدد مخططك مرة واحدة، ويمكن لكل من الواجهة الخلفية والواجهة الأمامية التحقق من الصحة وفقًا لنفس القواعد.

مخططات قاعدة البيانات

يدعم MongoDB التحقق من صحة مخطط JSON على مستوى المجموعة. يمكنك تعيين مدقق $jsonSchema يرفض أي مستند لا يتوافق مع مخططك عند الإدراج أو التحديث.

ملفات التكوين

تستخدم VS Code و ESLint والعديد من الأدوات الأخرى مخطط JSON للتحقق من صحة ملفات التكوين الخاصة بها. تلك الإكمال التلقائي الذي تحصل عليه عند تحرير tsconfig.json؟ يتم تشغيله بواسطة مخطط JSON.

مقارنة إصدارات المسودة

تطور مخطط JSON من خلال عدة مسودات. إليك تلك التي ستواجهها:

المسودةالسنةالإضافات الرئيسيةالحالة
Draft-042013المفردات الأساسية، $ref، الأنواع الأساسيةقديم (لا يزال مستخدمًا على نطاق واسع)
Draft-062017const، contains، propertyNamesقديم
Draft-072018if/then/else، readOnly، writeOnlyمدعوم على نطاق واسع
2019-092019$defs، unevaluatedProperties، dependentRequiredمدعوم من قبل المدققين الرئيسيين
2020-122020prefixItems (يحل محل التحقق من صحة التوائم)، $ref الديناميكيالحالي / الموصى به

للمشاريع الجديدة، استخدم 2020-12. إذا كنت بحاجة إلى أقصى توافق مع الأدوات الحالية، فإن Draft-07 هو الخيار الآمن - لديه دعم مكتبة شبه عالمي.

الأخطاء الشائعة التي يجب تجنبها

  • نسيان required. الخصائص المحددة تحت properties اختيارية بشكل افتراضي. إذا كان يجب أن يكون حقل موجودًا، قم بإدراجه في required.
  • خلط number و integer. number يقبل الأرقام العشرية؛ integer لا يقبل. استخدم integer للمعرفات، والعدادات، والقيم الأخرى الصحيحة.
  • تقييد أكثر من اللازم في وقت مبكر. ابدأ بالمخطط الأدنى الذي يلتقط الأخطاء الحقيقية. يمكنك دائمًا تشديد القيود لاحقًا - تخفيفها هو تغيير مكسور.
  • عدم استخدام $ref. تكرار نفس المخطط الفرعي في عدة أماكن هو كابوس للصيانة. استخرج الهياكل المشتركة إلى $defs.
  • تجاهل التحقق من صحة format. بشكل افتراضي، تتعامل معظم المدققات مع format كتعليق، وليس كقيود. تحتاج إلى تمكين التحقق من صحة التنسيق بشكل صريح (مثل ajv.addFormat() أو تمرير { validateFormats: true }).

جرب بنفسك: قم بإنشاء مخطط من أي عينة JSON باستخدام مولد مخطط JSON، ثم قم بتخصيص القيود لتتناسب مع متطلباتك.

أدوات ذات صلة