الـ strings
username.json
{ "type": "string", "minLength": 3, "maxLength": 20, "pattern": "^[a-z0-9_]+$"}- الـ
minLength/maxLength: بيعدّوا حروف Unicode (code points)، مش الـ.lengthبتاع JavaScript. الـ emoji😀طوله2في JS، بس Ajv بيعتبره حرف واحد، فبيفشل فيminLength: 2. - الـ
pattern: regex بصيغة ECMA-262 (زي JavaScript). جرّبنا"Ab"وطلع خطأين:must NOT have fewer than 3 charactersوmust match pattern "^[a-z0-9_]+$". - الـ backslash في JSON: لازم يتكتب مرتين، يعني
\dتبقى"\\d".
الـ format: أهم فخ في الـ strings
الـ format بيقول إن الـ string شكلها معروف: email، uri، date، date-time، time، uuid، ipv4، ipv6، hostname، duration، regex، json-pointer…
- في الـ standard (2019-09 و2020-12): الـ
formatannotation بس by default. يعني validator ماشي بالـ spec بالحرف ممكن يقبل"not-an-email"عادي. - في Ajv: الـ formats مش جوه Ajv نفسه. لو كتبت
format: "email"من غيرajv-formatsوstrictشغال، هيرمي:
output
unknown format "email" ignored in schema at path "#"- الحل:
pnpm add ajv-formatsوaddFormats(ajv)، وساعتها Ajv بيعامل الـ format كـ assertion. - تقدر تختار formats معينة:
addFormats(ajv, ["date", "email"]). - تقدر تقفلها خالص:
new Ajv({ validateFormats: false })، فالـ format يبقى توثيق بس.
formats.js
import Ajv from "ajv/dist/2020.js";import addFormats from "ajv-formats";const ajv = new Ajv({ allErrors: true });addFormats(ajv);const validate = ajv.compile({ type: "object", properties: { d: { type: "string", format: "date" }, t: { type: "string", format: "time" }, u: { type: "string", format: "uuid" }, e: { type: "string", format: "email" }, },});console.log(validate({ d: "2026-02-30", t: "10:00:00", u: "123", e: "a@b" }));for (const e of validate.errors) console.log(e.instancePath, e.message);output
false/d must match format "date"/t must match format "time"/u must match format "uuid"/e must match format "email"- الـ
dateبيفهم التقويم:2026-02-30مرفوض لأن فبراير مفيهوش ٣٠. - الـ
timeمحتاج timezone:10:00:00مرفوض، و10:00:00Zمقبول في ajv-formats. - الـ
emailتقريبي:a@bمرفوض وa@b.cمقبول. مفيش regex بيضمن إن الإيميل موجود فعلًا، فابعت رسالة تأكيد. - راجع الـ docs: ajv-formats عنده mode اسمه
fastوmode اسمهfull، وبيفرقوا في الدقة.
الأرقام
price.json
{ "type": "number", "exclusiveMinimum": 0, "maximum": 100, "multipleOf": 0.5}- الـ
minimum/maximum: شامل، يعني>=و<=. - الـ
exclusiveMinimum/exclusiveMaximum: رقم، ومش شامل، يعني>و<. هنا0مرفوض برسالةmust be > 0. - الـ
multipleOf: لازم يقبل القسمة.0.3مرفوض برسالةmust be multiple of 0.5. - في draft-04 كانت boolean:
"exclusiveMinimum": trueجنبminimum. في 2020-12 ده بيدي error:schema is invalid: data/exclusiveMinimum must be number.
الـ arrays
arrays.json
{ "type": "object", "properties": { "tags": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1, "maxItems": 5, "uniqueItems": true }, "location": { "type": "array", "prefixItems": [ { "type": "number", "minimum": -90, "maximum": 90 }, { "type": "number", "minimum": -180, "maximum": 180 } ], "items": false, "minItems": 2 }, "roles": { "type": "array", "contains": { "const": "owner" }, "minContains": 1, "maxContains": 1 } }}- الـ
items: schema كل عنصر في الـ array لازم يطابقها. - الـ
minItems/maxItems: عدد العناصر. حطmaxItemsدايمًا على input جاي من بره. - الـ
uniqueItems: ممنوع التكرار، والمقارنة deep، يعني[{"a":1},{"a":1}]مرفوضة. - الـ
prefixItems: tuple، كل مكان ليه schema.[30, 31]تمام. - الـ
items: falseبعدprefixItems: معناها ممنوع عناصر بعد الـ tuple.[30, 31, 5]بيترفض بـmust NOT have more than 2 items. - الـ
minItemsمع الـ tuple: من غيره[30]بيعدّي، لأنprefixItemsبيراجع الموجود بس. وAjv في strict mode بيطبع warning لو نسيته. - الـ
contains: لازم عنصر واحد على الأقل يطابق. ومعاهminContains/maxContainsللعدد. هنا لازم يبقى فيه owner واحد بالظبط.
الـ objects: قيود متقدمة
headers.json
{ "type": "object", "patternProperties": { "^x-": { "type": "string" } }, "propertyNames": { "pattern": "^[a-z-]+$" }, "minProperties": 1, "maxProperties": 30}- الـ
patternProperties: schema لكل حقل اسمه بيطابق regex. هنا أي حقل بيبدأ بـx-قيمته لازم string. - الـ
propertyNames: شرط على أسماء الحقول نفسها.{"Bad": "1"}بيترفض لأن فيه حرف capital. - الـ
minProperties/maxProperties: عدد الحقول.{}بيترفض بـmust NOT have fewer than 1 properties.
حقل بيستدعي حقل
payment.json
{ "type": "object", "properties": { "card": { "type": "string" }, "cvv": { "type": "string" }, "billing": { "type": "string" } }, "dependentRequired": { "card": ["cvv"] }, "dependentSchemas": { "card": { "required": ["billing"] } }}- الـ
dependentRequired: لوcardموجود، يبقىcvvلازم. الرسالة:must have property cvv when property card is present. - الـ
dependentSchemas: لوcardموجود، الـ object كله لازم يطابق schema تانية. أقوى منdependentRequired. - في draft-07 كانوا keyword واحد: اسمه
dependencies، واتقسم في 2019-09. - لو الشرط على قيمة الحقل مش وجوده: استخدم
if/then(فصل ٥).
خلّصت الفصل لما
🧠 اختبر نفسك
١) الـ pattern [0-9]{11} على رقم موبايل. فين المشكلة؟
مش anchored، فـ
abc01012345678xyz هيعدّي. الصح ^01[0125][0-9]{8}$.٢) كتبت format: email وAjv قبل not-an-email. ليه؟
غالبًا معملتش
addFormats(ajv) وstrict مقفول، أو شغال بـ validateFormats: false. في الـ spec نفسها الـ format annotation بس.٣) عايز array فيها نقطتين بالظبط (x, y) بالـ 2020-12؟
prefixItems فيها schemaين number، ومعاها items: false وminItems: 2.٤) سعر 19.99 اترفض مع multipleOf: 0.01. الحل؟
خزّنه integer بالقروش
1999، أو استخدم multipleOfPrecision في Ajv.