writing-json-schemas

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Writing JSON Schemas for z-schema

为z-schema编写JSON Schema

Write correct, idiomatic JSON Schemas validated by z-schema. Default target: draft-2020-12.
编写可通过z-schema验证的正确、符合规范的JSON Schema。默认目标版本:draft-2020-12

Schema template

Schema模板

Start every schema with a
$schema
declaration and
type
:
json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {},
  "required": [],
  "additionalProperties": false
}
Set
additionalProperties: false
explicitly when extra properties should be rejected — z-schema allows them by default.
每个schema都以
$schema
声明和
type
开头:
json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {},
  "required": [],
  "additionalProperties": false
}
当需要拒绝额外属性时,请显式设置
additionalProperties: false
—— z-schema默认允许额外属性。

Object schemas

对象Schema

Basic object with required fields

带必填字段的基础对象

json
{
  "type": "object",
  "properties": {
    "name": { "type": "string", "minLength": 1 },
    "email": { "type": "string", "format": "email" },
    "age": { "type": "integer", "minimum": 0, "maximum": 150 }
  },
  "required": ["name", "email"],
  "additionalProperties": false
}
json
{
  "type": "object",
  "properties": {
    "name": { "type": "string", "minLength": 1 },
    "email": { "type": "string", "format": "email" },
    "age": { "type": "integer", "minimum": 0, "maximum": 150 }
  },
  "required": ["name", "email"],
  "additionalProperties": false
}

Nested objects

嵌套对象

json
{
  "type": "object",
  "properties": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" },
        "zip": { "type": "string", "pattern": "^\\d{5}(-\\d{4})?$" }
      },
      "required": ["street", "city"]
    }
  }
}
json
{
  "type": "object",
  "properties": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" },
        "zip": { "type": "string", "pattern": "^\\\\d{5}(-\\\\d{4})?$" }
      },
      "required": ["street", "city"]
    }
  }
}

Dynamic property names

动态属性名

Use
patternProperties
to validate property keys by regex:
json
{
  "type": "object",
  "patternProperties": {
    "^x-": { "type": "string" }
  },
  "additionalProperties": false
}
Use
propertyNames
(draft-06+) to constrain all property key strings:
json
{
  "type": "object",
  "propertyNames": { "pattern": "^[a-z_]+$" }
}
使用
patternProperties
通过正则验证属性键:
json
{
  "type": "object",
  "patternProperties": {
    "^x-": { "type": "string" }
  },
  "additionalProperties": false
}
使用
propertyNames
(draft-06及以上版本)约束所有属性键字符串:
json
{
  "type": "object",
  "propertyNames": { "pattern": "^[a-z_]+$" }
}

Array schemas

数组Schema

Uniform array

统一类型数组

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

Tuple validation (draft-2020-12)

元组验证(draft-2020-12)

Use
prefixItems
for positional types,
items
for remaining elements:
json
{
  "type": "array",
  "prefixItems": [{ "type": "string" }, { "type": "integer" }],
  "items": false
}
items: false
rejects extra elements beyond the tuple positions.
使用
prefixItems
定义位置类型,
items
定义剩余元素的规则:
json
{
  "type": "array",
  "prefixItems": [{ "type": "string" }, { "type": "integer" }],
  "items": false
}
items: false
会拒绝元组位置之外的额外元素。

Contains (draft-06+)

Contains(draft-06及以上版本)

Require at least one matching item:
json
{
  "type": "array",
  "contains": { "type": "string", "const": "admin" }
}
With count constraints (draft-2019-09+):
json
{
  "type": "array",
  "contains": { "type": "integer", "minimum": 10 },
  "minContains": 2,
  "maxContains": 5
}
要求至少有一个匹配的元素:
json
{
  "type": "array",
  "contains": { "type": "string", "const": "admin" }
}
带计数约束(draft-2019-09及以上版本):
json
{
  "type": "array",
  "contains": { "type": "integer", "minimum": 10 },
  "minContains": 2,
  "maxContains": 5
}

String constraints

字符串约束

json
{
  "type": "string",
  "minLength": 1,
  "maxLength": 255,
  "pattern": "^[A-Za-z0-9_]+$"
}
json
{
  "type": "string",
  "minLength": 1,
  "maxLength": 255,
  "pattern": "^[A-Za-z0-9_]+$"
}

Format validation

格式验证

z-schema has built-in format validators:
date
,
date-time
,
time
,
email
,
idn-email
,
hostname
,
idn-hostname
,
ipv4
,
ipv6
,
uri
,
uri-reference
,
uri-template
,
iri
,
iri-reference
,
json-pointer
,
relative-json-pointer
,
regex
,
duration
,
uuid
.
json
{ "type": "string", "format": "date-time" }
Format assertions are always enforced by default (
formatAssertions: null
). For vocabulary-aware behavior in draft-2020-12, set
formatAssertions: true
on the validator.
z-schema内置了格式验证器:
date
date-time
time
email
idn-email
hostname
idn-hostname
ipv4
ipv6
uri
uri-reference
uri-template
iri
iri-reference
json-pointer
relative-json-pointer
regex
duration
uuid
json
{ "type": "string", "format": "date-time" }
格式断言默认始终强制执行(
formatAssertions: null
)。如果要使用draft-2020-12的词汇感知行为,请在验证器上设置
formatAssertions: true

Numeric constraints

数值约束

json
{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "multipleOf": 0.01
}
Use
exclusiveMinimum
/
exclusiveMaximum
for strict bounds:
json
{ "type": "integer", "exclusiveMinimum": 0, "exclusiveMaximum": 100 }
json
{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "multipleOf": 0.01
}
使用
exclusiveMinimum
/
exclusiveMaximum
设置严格边界:
json
{ "type": "integer", "exclusiveMinimum": 0, "exclusiveMaximum": 100 }

Combinators

组合器

anyOf
— match at least one

anyOf
—— 至少匹配一个

json
{
  "anyOf": [{ "type": "string" }, { "type": "number" }]
}
json
{
  "anyOf": [{ "type": "string" }, { "type": "number" }]
}

oneOf
— match exactly one

oneOf
—— 恰好匹配一个

json
{
  "oneOf": [
    { "type": "string", "maxLength": 5 },
    { "type": "string", "minLength": 10 }
  ]
}
json
{
  "oneOf": [
    { "type": "string", "maxLength": 5 },
    { "type": "string", "minLength": 10 }
  ]
}

allOf
— match all

allOf
—— 匹配所有

Use for schema composition. Combine base schemas with refinements:
json
{
  "allOf": [{ "$ref": "#/$defs/base" }, { "properties": { "extra": { "type": "string" } } }]
}
用于schema组合,将基础schema和细化规则结合:
json
{
  "allOf": [{ "$ref": "#/$defs/base" }, { "properties": { "extra": { "type": "string" } } }]
}

not
— must not match

not
—— 必须不匹配

json
{ "not": { "type": "null" } }
json
{ "not": { "type": "null" } }

if
/
then
/
else
(draft-07+)

if
/
then
/
else
(draft-07及以上版本)

Conditional validation — prefer over complex
oneOf
when the logic is "if X then require Y":
json
{
  "type": "object",
  "properties": {
    "type": { "type": "string", "enum": ["personal", "business"] },
    "company": { "type": "string" }
  },
  "if": { "properties": { "type": { "const": "business" } } },
  "then": { "required": ["company"] },
  "else": {}
}
条件验证 —— 当逻辑为“如果X则要求Y”时,优先使用而非复杂的
oneOf
json
{
  "type": "object",
  "properties": {
    "type": { "type": "string", "enum": ["personal", "business"] },
    "company": { "type": "string" }
  },
  "if": { "properties": { "type": { "const": "business" } } },
  "then": { "required": ["company"] },
  "else": {}
}

When to use which combinator

组合器选型参考

ScenarioUse
Value can be multiple types
anyOf
Exactly one variant must match
oneOf
Compose inherited schemas
allOf
"if condition then require fields"
if
/
then
/
else
Exclude a specific shape
not
Prefer
if
/
then
/
else
over
oneOf
when the condition is a single discriminator field — it produces clearer error messages.
场景使用组合器
值可以为多种类型
anyOf
必须恰好匹配一个变体
oneOf
组合继承的schema
allOf
"如果满足条件则要求某些字段"
if
/
then
/
else
排除特定结构
not
当条件是单个判别字段时,优先使用
if
/
then
/
else
而非
oneOf
—— 它会生成更清晰的错误信息。

Schema reuse with
$ref
and
$defs

使用
$ref
$defs
复用Schema

Local definitions

本地定义

json
{
  "$defs": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" }
      },
      "required": ["street", "city"]
    }
  },
  "type": "object",
  "properties": {
    "home": { "$ref": "#/$defs/address" },
    "work": { "$ref": "#/$defs/address" }
  }
}
json
{
  "$defs": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" }
      },
      "required": ["street", "city"]
    }
  },
  "type": "object",
  "properties": {
    "home": { "$ref": "#/$defs/address" },
    "work": { "$ref": "#/$defs/address" }
  }
}

Cross-schema references

跨Schema引用

Compile an array of schemas and reference by ID:
typescript
import ZSchema from 'z-schema';

const schemas = [
  {
    $id: 'address',
    type: 'object',
    properties: { city: { type: 'string' } },
    required: ['city'],
  },
  {
    $id: 'person',
    type: 'object',
    properties: {
      name: { type: 'string' },
      home: { $ref: 'address' },
    },
    required: ['name'],
  },
];

const validator = ZSchema.create();
validator.validateSchema(schemas);
validator.validate({ name: 'Alice', home: { city: 'Paris' } }, 'person');
编译schema数组并通过ID引用:
typescript
import ZSchema from 'z-schema';

const schemas = [
  {
    $id: 'address',
    type: 'object',
    properties: { city: { type: 'string' } },
    required: ['city'],
  },
  {
    $id: 'person',
    type: 'object',
    properties: {
      name: { type: 'string' },
      home: { $ref: 'address' },
    },
    required: ['name'],
  },
];

const validator = ZSchema.create();
validator.validateSchema(schemas);
validator.validate({ name: 'Alice', home: { city: 'Paris' } }, 'person');

Strict schemas with
unevaluatedProperties
(draft-2019-09+)

使用
unevaluatedProperties
编写严格Schema(draft-2019-09及以上版本)

When combining schemas with
allOf
,
additionalProperties: false
in a sub-schema blocks properties defined in sibling schemas. Use
unevaluatedProperties
instead — it tracks all properties evaluated across applicators:
json
{
  "allOf": [
    {
      "type": "object",
      "properties": { "name": { "type": "string" } },
      "required": ["name"]
    },
    {
      "type": "object",
      "properties": { "age": { "type": "integer" } }
    }
  ],
  "unevaluatedProperties": false
}
This accepts
{ "name": "Alice", "age": 30 }
but rejects
{ "name": "Alice", "age": 30, "extra": true }
.
当使用
allOf
组合schema时,子schema中的
additionalProperties: false
会阻止同级schema中定义的属性生效。请改用
unevaluatedProperties
—— 它会跟踪所有应用器中评估过的属性:
json
{
  "allOf": [
    {
      "type": "object",
      "properties": { "name": { "type": "string" } },
      "required": ["name"]
    },
    {
      "type": "object",
      "properties": { "age": { "type": "integer" } }
    }
  ],
  "unevaluatedProperties": false
}
上述配置会接受
{ "name": "Alice", "age": 30 }
,但会拒绝
{ "name": "Alice", "age": 30, "extra": true }

Validating the schema itself

验证Schema本身

Always validate schemas at startup:
typescript
const validator = ZSchema.create();
try {
  validator.validateSchema(schema);
} catch (err) {
  console.log('Schema errors:', err.details);
}
请始终在启动时验证schema:
typescript
const validator = ZSchema.create();
try {
  validator.validateSchema(schema);
} catch (err) {
  console.log('Schema errors:', err.details);
}

Common mistakes

常见错误

  • Forgetting
    additionalProperties
    : By default, extra properties are allowed. Set
    additionalProperties: false
    or use
    unevaluatedProperties: false
    to reject them.
  • Using
    additionalProperties: false
    with
    allOf
    : This blocks properties from sibling schemas. Use
    unevaluatedProperties: false
    at the top level instead (draft-2019-09+).
  • Array
    items
    in draft-2020-12
    : Use
    prefixItems
    for tuple validation.
    items
    now means "schema for remaining items".
  • Missing
    $schema
    : Without it, z-schema uses its configured default draft. Include
    $schema
    for explicit draft targeting.
  • definitions
    vs
    $defs
    : Both work, but
    $defs
    is the canonical form in draft-2019-09+. Use it consistently.
  • 忘记设置
    additionalProperties
    :默认情况下允许额外属性。设置
    additionalProperties: false
    或使用
    unevaluatedProperties: false
    来拒绝额外属性。
  • allOf
    中使用
    additionalProperties: false
    :这会阻止同级schema中的属性生效。请在顶层使用
    unevaluatedProperties: false
    替代(draft-2019-09及以上版本)。
  • draft-2020-12中的数组
    items
    :元组验证请使用
    prefixItems
    。现在
    items
    的含义是“剩余元素的schema”。
  • 缺少
    $schema
    :没有该声明时,z-schema会使用其配置的默认草案版本。请添加
    $schema
    显式指定目标版本。
  • definitions
    $defs
    的区别
    :两者都可用,但
    $defs
    是draft-2019-09及以上版本的规范写法,请统一使用。",