Skip to content
العودة إلى المدوّنة
دروس تعليمية

التحقق من JSON بـ JSON Schema 2026: دليل Ajv وPython والمتصفح

تحقّق من JSON باستخدام JSON Schema في Node وPython والمتصفح. ميزات Draft 2020-12، أنماط API حقيقية، وأمثلة جاهزة للنسخ. جرّب مجانًا.

12 دقيقة قراءة

التحقق من JSON Schema: التحقق من JSON في Node وPython والمتصفح (2026)

باختصار: JSON Schema هو عقد لبيانات JSON تُعرّف فيه أنواع الحقول والمفاتيح المطلوبة والقيود، ثم يتحقق المُدقّق مما إذا كانت أي وثيقة JSON تلتزم بهذا العقد. استعن بـAjv في Node لأسرع تحقق ممكن، وبمكتبة jsonschema في Python للمخططات القابلة للنقل بين اللغات، وادمج Ajv داخل المتصفح للحصول على ردود فورية في النماذج وملفات الإعدادات. أمّا Draft 2020-12 فهو الإصدار الأنسب للمشاريع الجديدة في 2026.

يبدأ هذا الدليل بأصغر مثال عملي، ثم ينتقل إلى أنماط متكاملة في بيئات التشغيل الثلاث، وينتهي بالمزالق الواقعية التي تُسبّب علل “التحقق ينجح لكن الإنتاج يرفض البيانات”.

ما هو JSON Schema (وما ليس هو)

تعريف في جملة واحدة

JSON Schema هو وثيقة JSON تصف شكل وثائق JSON أخرى. يقرأ المُدقّق المخطط والبيانات، ثم يؤكّد المطابقة أو يُعيد المسارات التي فشلت.

أصغر مثال مفيد:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": { "name": { "type": "string" } },
  "required": ["name"]
}

{"name": "Alice"} ينجح. {"age": 30} يفشل لغياب name. {"name": 42} يفشل لأن name ليس نصًّا. هذه فكرة المخططات بأكملها.

JSON Schema مقابل التحقق من صياغة JSON

كثيرًا ما يخلط المطورون بين هاتين المشكلتين، وهما مختلفتان تمامًا.

البُعدفحص صياغة JSONالتحقق بـJSON Schema
ما الذي يفحصههل هذه وثيقة JSON صحيحة نحويًّا؟هل تطابق هذه JSON العقد؟
ما يكتشفهفواصل ناقصة، علامات اقتباس مفردة، تعليقاتأنواع خاطئة، حقول مطلوبة مفقودة، قيم خارج المدى
الأدواتJSON.parse()، منسق JSONAjv، jsonschema (Pythonfastjsonschema
متى تلجأ إليهأوّل خطوة، قبل التحليل (parse)مباشرة بعد التحليل، قبل منطق الأعمال

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

JSON Schema مقابل JSONPath وJSON Patch وjq وTypeScript

تتنازع خمس أدوات هذه المساحة، ولكلٍّ منها مكانها:

الأداةالسؤال الذي تجيب عنهمتى تختارها
JSON Schemaهل تطابق JSON هذه البنية المتوقعة؟التحقق من مدخلات الـAPI وملفات الإعدادات وحمولات النماذج
JSONPathكيف أستخرج قيمة من هذه JSON؟استخراج حقول متداخلة، قراءات بالجملة
JSON Patch (RFC 6902)كيف أصف الفرق بين A وB؟تحرير تعاوني، مزامنة تزايدية
jqكيف أعالج JSON من سطر الأوامر؟سكربتات الصدفة، خطوط معالجة السجلات، فحوص الـCI
أنواع TypeScriptهل يستخدم كودي هذه البنية بشكل صحيح؟ضمانات وقت الترجمة داخل قاعدة كود واحدة

الفارق الجوهري: JSON Schema يتحقق من بيانات مجهولة في وقت التشغيل. TypeScript يتحقق من كود معلوم في وقت الترجمة. لا يستطيع TypeScript أن يساعدك مع JSON قادمة من webhook طرف ثالث أو من لصق المستخدم؛ هذا هو دور JSON Schema بالضبط. ويحتل Zod وPydantic منطقة وسطى (أنواع وقت ترجمة + تحقق وقت تشغيل)، وسنتحدث عنهما لاحقًا.

JSON Schema مقابل OpenAPI

من المفاهيم الشائعة الخاطئة أنّ OpenAPI يحلّ محلّ JSON Schema، وليس الأمر كذلك. يستعمل OpenAPI داخليًّا JSON Schema لوصف أجسام الطلبات والاستجابات، ثم يُضيف فوقها المسارات والمعاملات وأنماط الأمان وعناوين الخوادم. فالمخطط هو عقد شكل البيانات، وOpenAPI هو عقد الـAPI الذي يلفّه.

البُعدJSON SchemaOpenAPI
النطاقشكل وثيقة JSON واحدةشكل واجهة HTTP API كاملة
التبعياتلا توجد (المخطط JSON قائم بذاته)يستورد JSON Schema لتعريفات الأجسام
اقتران الإصداراتDraft 7 / Draft 2019-09 / Draft 2020-12يستخدم OpenAPI 3.0 مجموعة فرعية من Draft 4؛ ويستخدم OpenAPI 3.1 Draft 2020-12 أصلًا
الاستخدام النموذجيملفات الإعدادات، أغلفة الرسائل، تحقق النماذج، عقود حمولة واحدةتصميم REST API، توليد SDK، خوادم وهمية، اختبارات العقد
توليد الكودمحدود (بعض أدوات على نمط quicktype)منظومة ناضجة (openapi-generator، oapi-codegen، SDKات المزوّدين)
إدارة العقودملف لكل شكل، بلا توجيهمسارات وعمليات وتدفقات مصادقة ونقاط نهاية بإصدارات في وثيقة واحدة

اعتمد على JSON Schema وحده حين تكون القطعة التي تهمّك وثيقة واحدة: حمولة webhook، أو ملف إعدادات، أو رسالة طابور، أو نموذج. لا يوجد سطح HTTP لتوصيفه، فيكون OpenAPI عبئًا زائدًا.

أمّا OpenAPI فاختره حين تنشر واجهة HTTP API وتريد وثيقة واحدة تقود التوثيق وتوليد الـSDK والخوادم الوهمية واختبارات العقد. عرّف مخططاتك أوّلًا بوصفها ملفات JSON Schema مستقلة في مجلد schemas/، ثم أَشِر إليها بـ$ref من وثيقة OpenAPI. يبقي ذلك المخططات قابلة لإعادة الاستخدام خارج سياق الـAPI.

اقتران الإصدارات هو الفخ الذي تتعثّر فيه الفِرق. يستخدم OpenAPI 3.0 مجموعة فرعية من Draft 4، فلا يمكنك استعمال كلمات Draft 2020-12 مثل prefixItems أو unevaluatedProperties داخل وثيقة 3.0؛ ستتجاهلها المولّدات بصمت. أمّا OpenAPI 3.1 فهو امتداد لـDraft 2020-12، فأي شيء صالح في 2020-12 صالح فيه. إن كان الخيار بيدك، استهدف OpenAPI 3.1 واكتب مخططات Draft 2020-12 في كل مكان.

أول JSON Schema لك (5 دقائق)

الكلمات المفتاحية التي تحتاج إليها أوّلًا

تكفي هذه المفردات لتغطية أغلب حالات التحقق التي ستصادفها:

{
  "type": "object",
  "properties": {
    "id":       { "type": "integer", "minimum": 1 },
    "email":    { "type": "string", "format": "email" },
    "age":      { "type": "integer", "minimum": 0, "maximum": 150 },
    "tags":     { "type": "array", "items": { "type": "string" }, "minItems": 1 },
    "role":     { "enum": ["admin", "editor", "viewer"] },
    "metadata": { "type": "object", "additionalProperties": true }
  },
  "required": ["id", "email"],
  "additionalProperties": false
}

المفردات:

  • typestring، number، integer، boolean، null، array، object
  • properties + required — تعريف الحقول وتحديد الإلزامي منها
  • enum / const — التقييد بمجموعة محددة أو قيمة حرفية واحدة
  • minimum / maximum / multipleOf — حدود عددية
  • minLength / maxLength / pattern — طول النص والتعبير النمطي
  • minItems / maxItems / uniqueItems — شكل المصفوفة
  • additionalProperties: false — رفض المفاتيح غير المُعلنة (اضبطها دائمًا في عقود الإدخال)

أمثلة JSON Schema بحسب حالة الاستخدام

تظهر الكلمات المفتاحية أعلاه في تركيبات مختلفة بحسب ما تتحقق منه. في ما يلي عدد من الأشكال التمثيلية:

جسم طلب API — نقطة نهاية تسجيل تقبل بريدًا إلكترونيًّا وكلمة مرور:

{
  "type": "object",
  "properties": {
    "email":    { "type": "string", "format": "email" },
    "password": { "type": "string", "minLength": 8, "maxLength": 128 }
  },
  "required": ["email", "password"],
  "additionalProperties": false
}

ملف إعدادات — إعداد مُسجِّل يُقيّد المستوى بمجموعة محددة:

{
  "type": "object",
  "properties": {
    "level":  { "enum": ["debug", "info", "warn", "error"] },
    "output": { "type": "string", "default": "stdout" }
  },
  "required": ["level"],
  "additionalProperties": false
}

حمولة نموذج بقواعد شرطية — حين تكون قيمة accountType هي "business" يصبح taxId مطلوبًا:

{
  "type": "object",
  "properties": {
    "accountType": { "enum": ["personal", "business"] },
    "taxId":       { "type": "string" }
  },
  "if":   { "properties": { "accountType": { "const": "business" } } },
  "then": { "required": ["taxId"] }
}

سجلّ JSON لصف CSV — صف واحد من جدول طلبات مُصدَّر:

{
  "type": "object",
  "properties": {
    "orderId":   { "type": "string", "pattern": "^ORD-[0-9]{6}$" },
    "orderedOn": { "type": "string", "format": "date" },
    "totalUsd":  { "type": "number", "minimum": 0 }
  },
  "required": ["orderId", "orderedOn", "totalUsd"]
}

غلاف حدث webhook — يُميّز oneOf بين الأنواع عبر القيمة الحرفية في type، فيكون لكل نوع حدث شكل حمولة مستقل:

{
  "oneOf": [
    { "properties": { "type": { "const": "order.created" }, "data": { "$ref": "#/$defs/order" } } },
    { "properties": { "type": { "const": "order.refunded" }, "data": { "$ref": "#/$defs/refund" } } }
  ]
}

تغطّي هذه الأمثلة الخمسة جلّ ما تكتبه الفِرق عمليًّا. انسخ الأقرب إلى حالتك وعدّل أسماء الحقول؛ قاموس الكلمات المفتاحية يبقى كما هو.

تحقق دون تثبيت أي شيء

ألصق المخطط والحمولة في ملعب ajv.js.org أو jsonschemavalidator.net لحكم فوري. وإن بدا الـJSON نفسه مريبًا، مرّره أوّلًا عبر منسق JSON.

التحقق في Node.js باستخدام Ajv

التثبيت ومثال من 12 سطرًا

يُجمّع Ajv مخططك إلى دالة محسَّنة عند أوّل استدعاء لـcompile، ثم يعيد استخدامها.

npm install ajv
import Ajv from "ajv";
const ajv = new Ajv();

const schema = {
  type: "object",
  properties: {
    name: { type: "string" },
    age:  { type: "integer", minimum: 0 }
  },
  required: ["name"]
};

const validate = ajv.compile(schema);
const data = { name: "Alice", age: 30 };

if (!validate(data)) console.log(validate.errors);
else                  console.log("OK");

التحويل إلى Draft 2020-12

ما زال البنّاء الافتراضي Ajv مثبَّتًا على Draft 7 للحفاظ على التوافق الخلفي. اشترك في 2020-12 صراحةً:

import Ajv2020 from "ajv/dist/2020";
const ajv = new Ajv2020({ strict: true, allErrors: true });

الآن أصبحت prefixItems وunevaluatedProperties و$dynamicRef متاحة. راجع قسم Draft 2020-12 أدناه لمعرفة وظيفة كلٍّ منها.

تشغيل التحقق من format

يتعثّر المطورون في هذه النقطة أكثر من غيرها مع Ajv: format: "email" لا يفعل شيئًا افتراضيًّا. تتعامل المواصفة مع format بوصفه إرشاديًّا، فعليك تسجيل وحدة الصيغ بنفسك:

npm install ajv-formats
import addFormats from "ajv-formats";
addFormats(ajv);  // الآن "format": "email" يتحقق فعليًّا

دون هذه الخطوة، يَعبُر {"email": "not-an-email"} مخططًا يطلب format: "email". ثبّت دائمًا ajv-formats في الإنتاج.

وسيط Express الإنتاجي

مُدقّق واحد لكل مسار، يُجمَّع مرة واحدة عند بدء التشغيل:

import express from "express";
import Ajv2020 from "ajv/dist/2020";
import addFormats from "ajv-formats";

const ajv = new Ajv2020({ allErrors: true });
addFormats(ajv);

const validateUser = ajv.compile({
  type: "object",
  properties: {
    email: { type: "string", format: "email" },
    age:   { type: "integer", minimum: 13 }
  },
  required: ["email"],
  additionalProperties: false
});

const app = express();
app.use(express.json());

app.post("/users", (req, res) => {
  if (!validateUser(req.body)) {
    return res.status(400).json({ errors: validateUser.errors });
  }
  // ... منطق الأعمال
  res.status(201).json({ ok: true });
});

الخطأ الذي يكلّف أكثر من غيره هو استدعاء ajv.compile(schema) داخل مُعالج الطلب. جمِّع المخطط مرة واحدة في نطاق الوحدة، ثم أعِد استخدام الدالة العائدة. إعادة التجميع مع كل طلب تُسقط الإنتاجية بمعدل 50× أو أكثر.

التحقق في Python باستخدام jsonschema

التثبيت والاستخدام الأساسي

pip install jsonschema
from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age":  {"type": "integer", "minimum": 0}
    },
    "required": ["name"]
}

try:
    validate(instance={"name": "Alice", "age": 30}, schema=schema)
    print("OK")
except ValidationError as e:
    print("FAIL:", e.message, "at", list(e.absolute_path))

تجميع كل الأخطاء عبر Draft202012Validator

تَطرح validate() عند أوّل خطأ. ولسرد كل المشكلات دفعةً واحدة (وهو مفيد لردود النماذج)، استخدم iter_errors:

from jsonschema import Draft202012Validator

validator = Draft202012Validator(schema)
errors = sorted(validator.iter_errors(instance), key=lambda e: e.path)
for err in errors:
    print(f"  - {'/'.join(map(str, err.absolute_path))}: {err.message}")

يستطيع المستخدم بهذا تصحيح أخطاء النموذج كلها في تمريرة واحدة بدل أن يُرسله الخادم ذهابًا وإيابًا.

jsonschema مقابل Pydantic: متى تختار أيًّا منهما

تحلّ المكتبتان مشكلتين مختلفتين، ويستفيد كثير من الفرق منهما معًا.

البُعدjsonschemaPydantic v2
صيغة المخططقاموس JSON (المخطط بيانات)صنف Python بتلميحات نوع
الأداءمفسَّر، أبطأ بـ10–100× من Pydanticنواة Rust، الأسرع في النظام البيئي
القابلية للنقل بين اللغاتنعم (المخطط نفسه يعمل في JS وGo وRust)لا (Python فقط)
تكامل أصلي مع FastAPI / النماذجتحويل يدويجاهز
كلمات Draft 2020-12 الكاملة ($dynamicRef ونحوها)كاملةجزئية

القاعدة التي تصمد في الإنتاج: استخدم jsonschema لعقود متعددة اللغات (OpenAPI، الـAPIات العامة، الـwebhooks)؛ واستخدم Pydantic لخدمات Python الداخلية. كثير من الفِرق يشغّلان الاثنين معًا: jsonschema عند البوابة لفرض العقد، وPydantic في طبقة التطبيق لمنطق أعمال مُحكم النوع. المخطط هو القطعة المنقولة، مطابق تمامًا لما ستُغذّيه إلى Ajv.

التحقق في المتصفح

لماذا التحقق من جانب العميل أصلًا

أوّل المكاسب يخصّ تجربة الاستخدام: تغذية راجعة فورية أثناء الكتابة تُقصّر دورة الإصلاح كثيرًا مقارنة بانتظار رد الخادم. وثانيها يُريح عرض النطاق، إذ لا تغادر الأخطاء الواضحة المتصفح أصلًا. وثالثها يُحسّن نظافة الواجهة الخلفية بتقليل الحمولات المعطوبة الواصلة إليها، وإن كان لا يحلّ محل التحقق على الخادم.

ولا تثق بتحقق العميل وحده مهما كان متينًا. أعِد التحقق على الخادم دائمًا.

تحزيم Ajv للمتصفح

npm install ajv ajv-formats
import Ajv2020 from "ajv/dist/2020";
import addFormats from "ajv-formats";

const ajv = new Ajv2020({ allErrors: true });
addFormats(ajv);

export const validateForm = ajv.compile({
  type: "object",
  properties: {
    email:    { type: "string", format: "email" },
    password: { type: "string", minLength: 8 }
  },
  required: ["email", "password"]
});

تضيف الحزمة نحو 30 كيلوبايت بعد gzip، وهو قدر معتبر يستحق الموازنة. تشحن الفرق Ajv عادةً حين تحتاج إلى تعريف مخطط واحد يتشاركه الخادم والعميل.

بدائل أخف: Zod وValibot

إن لم تكن بحاجة إلى منظومة JSON Schema، وكنت أصلًا في TypeScript، فإن مُدقّقًا أصيلًا في TS يمنحك حِزمًا أصغر واستنتاج أنواع أدق:

import { z } from "zod";
const UserSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
});
const result = UserSchema.safeParse(data);
if (!result.success) console.log(result.error.issues);

يأتي Valibot بنحو 3 كيلوبايت بعد gzip بواجهة برمجية مشابهة، وهو الخيار الأنسب حين يكون حجم الحزمة هو الاعتبار الأول. لكن انتبه إلى أن أيًّا من المكتبتين لا يُنتج JSON Schema. إن احتجت مصدرًا واحدًا للحقيقة يتشاركه الخوادم وعملاء الأطراف الثالثة أو مولّدات OpenAPI، فابقَ على Ajv. أما إن كان كامل المسار TypeScript داخليًّا فيكفيك Zod أو Valibot.

ما الذي يضيفه Draft 2020-12

prefixItems للتحقق من الصفائف الموقعية (tuples)

كان Draft 7 يُعبّر عن الـtuples عبر items: [] مع additionalItems. أمّا Draft 2020-12 فيفصل بينهما بنظافة:

{
  "type": "array",
  "prefixItems": [
    { "type": "string" },
    { "type": "number" }
  ],
  "items": false
}

["x", 42] ينجح. ["x", 42, "extra"] يفشل. يُقرأ المخطط تمامًا كما يفعل.

unevaluatedProperties للمخططات المُركّبة

يقع كل فريق يستخدم allOf أو oneOf في الفخّ نفسه: additionalProperties: false لا يفحص إلا المستوى الذي يَظهر فيه مباشرة، أما الأخوات داخل allOf فتعلن من الخصائص ما تشاء. يحلّ 2020-12 هذه المشكلة عبر unevaluatedProperties: false:

{
  "allOf": [
    { "$ref": "#/$defs/base" }
  ],
  "unevaluatedProperties": false
}

يرفض هذا أي خاصية لم يُقيّمها أيٌّ من الفروع، وهو السلوك الذي يتوقعه معظم المطورين من additionalProperties: false.

$dynamicRef للمخططات العَوْدية (recursive)

يعرف كل من حاول التصريح بمخطط شجرة عَوْدية في Draft 7 كم يحتاج الأمر من التفافات. يأتي $dynamicRef مع $dynamicAnchor لتنظيف هذا الجزء:

{
  "$dynamicAnchor": "node",
  "type": "object",
  "properties": {
    "value": { "type": "string" },
    "children": { "type": "array", "items": { "$dynamicRef": "#node" } }
  }
}

يجعل هذا العَوْدية تصريحية، ويمكن للمخططات المنحدرة أن تتجاوزها دون أن تُعيد كتابة $id.

Draft 7 مقابل 2020-12: أيهما تختار

  • مشروع جديد، أدوات حديثة → Draft 2020-12
  • بناء أو استهلاك OpenAPI 3.1 → 2020-12 هو لهجته الأصلية
  • التعامل مع OpenAPI 3.0 أو خدمات أقدم → Draft 4 (يستخدم OpenAPI 3.0 مجموعة فرعية من Draft 4؛ لا تخلط اللهجات)
  • الحاجة إلى توافق واسع مع المُدقّقات (Postman، أدوات CI القديمة) → ما زال Draft 7 أأمن صيغة تبادل

كل مُدقّق حديث (Ajv، jsonschema في Python، jsonschema-rs، وnetworknt/json-schema-validator في Java) يدعم 2020-12 اليوم.

أنماط من العالم الواقعي

التحقق من مدخلات الـAPI

يمثّل وسيط Express أعلاه الشكل الإنتاجي المباشر. وفوق ذلك، احتفظ بكل المخططات في مجلد schemas/ بجذر المستودع، وأضف خطوة CI تُشغّل ajv test (أو ما يكافئه في Python) لتتأكد من أن المخططات نفسها مطابقة لميتا-مخطط JSON Schema.

ملفات الإعدادات

يأتي Visual Studio Code مدمَجًا مع تكامل SchemaStore: إكمال تلقائي وتحقق فوري لـpackage.json وtsconfig.json وعشرات غيرها. أضف حقل $schema إلى ملفات إعداداتك ينلْ مستخدمو المحرر المعاملة نفسها.

تركيبات اختبار الـCI

تتعفّن تركيبات الاختبار. يُحدّث أحدهم النموذج، فتظل التركيبة على شكلها القديم، ويظل الاختبار ناجحًا لأن التأكيدات لم تمسّ الحقل المتغير. التقط هذا بفحص مخطط قبل تنفيذ التأكيدات:

import { glob } from "glob";
const files = await glob("__tests__/fixtures/*.json");
for (const f of files) {
  const data = JSON.parse(await fs.readFile(f, "utf8"));
  if (!validate(data)) throw new Error(`${f}: ${ajv.errorsText(validate.errors)}`);
}

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

حمولات الـWebhook (Stripe، GitHub)

تُعدّ webhooks الأطراف الثالثة من أنسب الأماكن لتطبيق JSON Schema، فالـwebhook عقدٌ يستطيع المزوّد تغييره في أي لحظة، وأنت بحاجة إلى أن تعلم بذلك فور حدوثه. ينشر كلٌّ من Stripe وGitHub أوصاف OpenAPI يمكنك أن تستخرج منها JSON Schemas. تحقّق من الأحداث الواردة، فأي تحديث كاسر يُشعل مراقبتك بدل أن يُفسد الحالة في صمت.

التحقق من النماذج المُساق بالمخطط

يأتي React Hook Form بمُهيّئ @hookform/resolvers/ajv، ولدى VeeValidate في Vue مكافئ يعتمد على Ajv. يقود كلاهما عرض النموذج ورسائل الخطأ وتحقق التقديم من خلال JSON Schema واحد، فيبقى المخطط مرجعًا وحيدًا تَرِث الواجهة قواعده مباشرة.

رسائل أخطاء ودودة

لماذا تكون الافتراضات خشنة

يُنتج Ajv افتراضيًّا أخطاءً من نوع #/properties/email format must match "email". هذا الشكل مقبول لمهندس يصحّح خطأ 400، لكنه عديم الفائدة لمستخدم يحاول إكمال نموذج دفع.

ajv-errors لرسائل مخصّصة

npm install ajv-errors
import ajvErrors from "ajv-errors";
ajvErrors(ajv);

const schema = {
  type: "object",
  properties: { email: { type: "string", format: "email" } },
  required: ["email"],
  errorMessage: {
    properties: { email: "يرجى إدخال عنوان بريد إلكتروني صالح" },
    required: { email: "البريد الإلكتروني مطلوب" }
  }
};

تبقى كلمة errorMessage داخل المخطط، فتنتقل قواعد التحقق ونصوص الواجهة معًا حيثما انتقل الملف.

ajv-i18n للأخطاء المترجمة

تأتي ajv-i18n بترجمات للرسائل الافتراضية في أكثر من 30 لغة. يكفي سطر واحد عند بدء التشغيل لتُصدر رسائلك بأي لغة من قائمتها. تنفع بوصفها احتياطًا حين لا تغطي تجاوزات errorMessage جميع القيود.

تخطيط مسارات المخطط على حقول النموذج

لكل خطأ في Ajv حقل instancePath مثل /users/0/email. تتوقع معظم مكتبات النماذج مسارات منقوطة مثل users[0].email. سطر واحد:

const fieldPath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");

في jsonschema الخاصة بـPython، يقع المُكافئ في error.absolute_path. اربطها بـ. للحصول على الأثر نفسه.

خمس مزالق تَعبُر التحقق ثم تُسقط الإنتاج

1. format إرشادي افتراضيًّا

دون ajv-formats مع addFormats(ajv)، فإن كل كلمة format تكون بلا أثر. {"format": "email"} يقبل "not-an-email". ثبّت دائمًا حزمة الصيغ في الإنتاج.

2. additionalProperties افتراضه true

يقبل مخططك دون additionalProperties: false كل حقل غير معلَن، فيستطيع العملاء شحن حقول إضافية تتجاوز التحقق كليًّا. اجعله افتراضيًّا في عقود الإدخال، ثم خفّف القيود حيث تحتاج إلى ذلك بوعي.

3. additionalProperties لا يَتركّب

داخل allOf أو oneOf أو anyOf، لا يفحص additionalProperties: false إلا الخصائص في مستواه الخاص. وتنزلق الأخوات منه. حلّ Draft 2020-12 هو unevaluatedProperties: false.

4. $ref البعيد مخاطرة إنتاج

يُجبر $ref: "https://example.com/schema.json" Ajv على الجلب عبر الشبكة عند أوّل تجميع. النتيجة زمن استجابة إضافي، وتعرّض لخدمة DoS إن تعطّل المضيف البعيد، فضلًا عن سطح هجوم MITM. ضمّن أهداف $ref داخل المخطط مباشرة، أو حمّلها من القرص في وقت البناء.

5. المخططات المُولَّدة تنحرف عن البيانات الحقيقية

تُولّد أدوات مثل quicktype وtypescript-json-schema مخططات انطلاقًا من أنواع موجودة، لكن الناتج يأتي عادةً متساهلًا أكثر مما يجب: كل حقل اختياري، وadditionalProperties مفتوح. تعامل مع هذه المخططات بوصفها مسوَّدات، وشدّد قيودها يدويًّا، ثم أَطلِق فحص CI يُقارن عيّنات الإنتاج الحقيقية بالمخطط في الاتجاهين كي تنكشف أي انحرافات مبكرًا.

الأداء: أرقام وقواعد إبهام

  • Ajv (Node.js) — تُنجز المُدقّقات المُجمَّعة فحصًا واحدًا في أقل بكثير من ميكروثانية، وهو أسرع مُدقّق JS جاهز للإنتاج بين المتاح اليوم.
  • jsonschema (Python) — مفسَّر، أبطأ بـ10–100× من Pydantic. استبدله بـ**fastjsonschema** حين يعضّ ذلك؛ فهو يُولّد كود Python ويقترب من Ajv.
  • Rust وGo — يمنحك jsonschema-rs وxeipuuv/gojsonschema 2–5× إضافية فوق Ajv في طبقة البوابة.
  • أكبر مكسب منفرد — التجميع المُسبق. ajv.compile(schema) مرة واحدة عند تحميل الوحدة، وأعِد استخدام المُدقّق العائد في كل طلب. إعادة التجميع لكل طلب تقتل الإنتاجية بـ50× أو أكثر.

الأسئلة الشائعة

ما هو التحقق من JSON Schema بلغة بسيطة؟

التحقق من JSON Schema يفحص ما إذا كانت وثيقة JSON تتبع عقدًا. العقد (المخطط) هو نفسه JSON، يُعلن الأنواع والحقول المطلوبة والقيود. يقرأ المُدقّق المخطط والبيانات ويُبلغ بـ”نجح” أو بالمسارات التي فشلت ولماذا.

كيف أتحقق من JSON مقابل مخطط عبر الإنترنت؟

ألصق المخطط والبيانات في ملعب ajv.js.org أو jsonschemavalidator.net لحكم فوري. وإن بدا الـJSON مشوّهًا، نظّفه أوّلًا في منسق JSON؛ كلاهما يعمل في المتصفح، دون رفع.

أيّ مُدقّق JSON Schema هو الأسرع في 2026؟

في Node، يُنجز Ajv بمُدقّقات مُجمَّعة مسبقًا فحصًا واحدًا في أقل من ميكروثانية. في Python، يُولّد fastjsonschema كودًا ويبلغ إنتاجية بمستوى Ajv. في طبقة البوابة، jsonschema-rs (Rust) و**gojsonschema** (Go) أسرع من Ajv بـ2–5×. أيًّا اخترت، جمّع مرة واحدة وأعِد الاستخدام.

ما الفرق بين JSON Schema وأنواع TypeScript؟

يفحص TypeScript الكود الذي تكتبه في وقت الترجمة. ويفحص JSON Schema JSON مجهولة في وقت التشغيل. لا يستطيع TypeScript أن يرى JSON الواصلة من استجابة HTTP أو من ملف أو من لصق مستخدم؛ وهذا بالضبط ما يُؤديه JSON Schema.

هل أستخدم Draft 2020-12 أم Draft 7؟

للمشاريع الجديدة في 2026، اختر Draft 2020-12. تحلّ prefixItems وunevaluatedProperties و$dynamicRef مشكلات حقيقية. يستخدم OpenAPI 3.1 2020-12 أصلًا. ابقَ على Draft 7 فقط لأجل توافق Postman أو الخدمات الأقدم. يستخدم OpenAPI 3.0 مجموعة فرعية من Draft 4؛ لا تخلط اللهجات.

كيف أُولّد JSON Schema من JSON موجود؟

ثلاث خيارات: ألصق العيّنات في quicktype.io أو jsonschema.net؛ أو شغّل npx genson-js أو pip install genson && genson sample.json من سطر الأوامر؛ أو اكتبه يدويًّا. المخططات المولَّدة آليًّا متساهلة جدًّا (كل حقل اختياري، additionalProperties: true)، فشدّدها دائمًا قبل التعامل معها بوصفها عقودًا.

هل يمكن لـJSON Schema أن يحلّ محل OpenAPI؟

لا. يستخدم OpenAPI JSON Schema داخليًّا لوصف أجسام الطلبات والاستجابات، ثم يُضيف المسارات وأنماط الأمان والمعاملات وعناوين الخوادم. يتركّبان معًا: اكتب مخططاتك، أَشِر إليها من وثيقة OpenAPI، ستحصل على عقود API كاملة.

هل JSON Schema هو نفسه JSONPath أو jq؟

مشكلات مختلفة. يتحقق JSON Schema من البنية (“هل تطابق هذه JSON العقد؟”). أمّا JSONPath وjq فيستخرجان القيم (“اسم كل pod في طور Running”). تحقّق بمخطط؛ واستعلم بـJSONPath أو jq.

لماذا ينجح تحقق Ajv لكن الإنتاج يرفض البيانات؟

ثلاثة أسباب تغطي تقريبًا كل الحالات: نسيان ajv-formats فلم يتحقق format: "email" قطّ، أو حذف additionalProperties: false فتسلّلت حقول إضافية من العميل، أو استخدام additionalProperties: false داخل allOf أو oneOf ثم اكتشاف أنه لا يَتركّب. عالج الحالة الأخيرة بالانتقال إلى unevaluatedProperties: false.

هل يمكنني تخصيص رسائل أخطاء JSON Schema للمستخدمين النهائيين؟

نعم. في Node، ثبّت ajv-errors لتضمين errorMessage داخل المخطط، وajv-i18n لترجمات تتجاوز 30 لغة. في Python، تُتيح jsonschema سياق التحقق الكامل في كل كائن خطأ، فتستطيع أن تُسقِط نوع الخطأ مع المسار على أي نص يستخدمه نظام تصميمك.

مقالات ذات صلة

عرض جميع المقالات