migrating-json-schemas

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Migrating JSON Schemas Between Drafts

JSON Schema草案版本迁移

z-schema supports draft-04, draft-06, draft-07, draft-2019-09, and draft-2020-12. This skill covers migrating schemas between drafts and verifying them with z-schema.
z-schema支持draft-04、draft-06、draft-07、draft-2019-09和draft-2020-12。本技能覆盖不同草案版本间的schema迁移,以及如何使用z-schema对其进行验证。

Migration workflow

迁移工作流

  1. Identify the source draft (check
    $schema
    or
    id
    /
    $id
    usage).
  2. Set the target version on the validator:
    typescript
    import ZSchema from 'z-schema';
    const validator = ZSchema.create({ version: 'draft2020-12' });
  3. Run
    validator.validateSchema(schema)
    to surface incompatibilities.
  4. Fix each reported error using the keyword mapping below.
  5. Re-validate until the schema passes.
  1. 确定源草案版本(检查
    $schema
    id
    /
    $id
    的使用情况)。
  2. 在验证器上设置目标版本:
    typescript
    import ZSchema from 'z-schema';
    const validator = ZSchema.create({ version: 'draft2020-12' });
  3. 运行
    validator.validateSchema(schema)
    来排查不兼容问题。
  4. 使用下方的关键字映射修复每个上报的错误。
  5. 重新验证直到schema通过校验。

Quick reference: keyword changes

快速参考:关键字变更

Old keyword (draft-04)New keyword (draft-2020-12)Introduced in
id
$id
draft-06
definitions
$defs
draft-2019-09
Array-form
items
(tuple)
prefixItems
draft-2020-12
additionalItems
items
(when
prefixItems
present)
draft-2020-12
exclusiveMinimum: true
(boolean)
exclusiveMinimum: <number>
draft-06
exclusiveMaximum: true
(boolean)
exclusiveMaximum: <number>
draft-06
dependencies
(string arrays)
dependentRequired
draft-2019-09
dependencies
(schema values)
dependentSchemas
draft-2019-09
$recursiveRef
/
$recursiveAnchor
$dynamicRef
/
$dynamicAnchor
draft-2020-12
For the complete keyword mapping with examples, see references/keyword-mapping.md.
旧关键字(draft-04)新关键字(draft-2020-12)引入版本
id
$id
draft-06
definitions
$defs
draft-2019-09
数组形式
items
(元组)
prefixItems
draft-2020-12
additionalItems
items
(存在
prefixItems
时)
draft-2020-12
exclusiveMinimum: true
(布尔型)
exclusiveMinimum: <number>
draft-06
exclusiveMaximum: true
(布尔型)
exclusiveMaximum: <number>
draft-06
dependencies
(字符串数组)
dependentRequired
draft-2019-09
dependencies
(schema值)
dependentSchemas
draft-2019-09
$recursiveRef
/
$recursiveAnchor
$dynamicRef
/
$dynamicAnchor
draft-2020-12
完整带示例的关键字映射请查看 references/keyword-mapping.md

Common migration paths

常见迁移路径

Draft-04 → Draft-2020-12

Draft-04 → Draft-2020-12

This is the largest jump. Apply changes in order:
1. Rename
id
to
$id
json
// Before (draft-04)
{ "id": "http://example.com/person.json", "type": "object" }

// After (draft-2020-12)
{ "$id": "http://example.com/person.json", "type": "object" }
2. Convert boolean
exclusiveMinimum
/
exclusiveMaximum
to numeric
json
// Before (draft-04)
{ "type": "number", "minimum": 0, "exclusiveMinimum": true }

// After (draft-2020-12)
{ "type": "number", "exclusiveMinimum": 0 }
Note: the
minimum
keyword is removed when converting to
exclusiveMinimum
as a number, since
exclusiveMinimum: 0
means "greater than 0".
3. Rename
definitions
to
$defs
json
// Before
{ "definitions": { "address": { "type": "object" } } }

// After
{ "$defs": { "address": { "type": "object" } } }
Update all
$ref
values that point to
#/definitions/...
#/$defs/...
.
4. Split
dependencies
json
// Before (draft-04) — mixed dependencies
{
  "dependencies": {
    "billing_address": ["credit_card"],
    "credit_card": { "type": "object", "properties": { "cvv": { "type": "string" } } }
  }
}

// After (draft-2020-12) — split into two keywords
{
  "dependentRequired": {
    "billing_address": ["credit_card"]
  },
  "dependentSchemas": {
    "credit_card": { "type": "object", "properties": { "cvv": { "type": "string" } } }
  }
}
5. Convert tuple
items
to
prefixItems
json
// Before (draft-04)
{
  "type": "array",
  "items": [{ "type": "string" }, { "type": "number" }],
  "additionalItems": false
}

// After (draft-2020-12)
{
  "type": "array",
  "prefixItems": [{ "type": "string" }, { "type": "number" }],
  "items": false
}
When
items
was an array (tuple validation), it becomes
prefixItems
. The old
additionalItems
becomes
items
.
6. Add
$schema
declaration
json
{ "$schema": "https://json-schema.org/draft/2020-12/schema" }
这是跨度最大的版本升级,请按顺序应用变更:
1. 将
id
重命名为
$id
json
// Before (draft-04)
{ "id": "http://example.com/person.json", "type": "object" }

// After (draft-2020-12)
{ "$id": "http://example.com/person.json", "type": "object" }
2. 将布尔型的
exclusiveMinimum
/
exclusiveMaximum
转换为数值型
json
// Before (draft-04)
{ "type": "number", "minimum": 0, "exclusiveMinimum": true }

// After (draft-2020-12)
{ "type": "number", "exclusiveMinimum": 0 }
注意:转换为数值型
exclusiveMinimum
时会移除
minimum
关键字,因为
exclusiveMinimum: 0
表示“大于0”。
3. 将
definitions
重命名为
$defs
json
// Before
{ "definitions": { "address": { "type": "object" } } }

// After
{ "$defs": { "address": { "type": "object" } } }
将所有指向
#/definitions/...
$ref
值更新为
#/$defs/...
4. 拆分
dependencies
json
// Before (draft-04) — 混合依赖
{
  "dependencies": {
    "billing_address": ["credit_card"],
    "credit_card": { "type": "object", "properties": { "cvv": { "type": "string" } } }
  }
}

// After (draft-2020-12) — 拆分为两个关键字
{
  "dependentRequired": {
    "billing_address": ["credit_card"]
  },
  "dependentSchemas": {
    "credit_card": { "type": "object", "properties": { "cvv": { "type": "string" } } }
  }
}
5. 将元组形式的
items
转换为
prefixItems
json
// Before (draft-04)
{
  "type": "array",
  "items": [{ "type": "string" }, { "type": "number" }],
  "additionalItems": false
}

// After (draft-2020-12)
{
  "type": "array",
  "prefixItems": [{ "type": "string" }, { "type": "number" }],
  "items": false
}
items
为数组(元组校验)时,它会变为
prefixItems
,旧的
additionalItems
则变为
items
6. 添加
$schema
声明
json
{ "$schema": "https://json-schema.org/draft/2020-12/schema" }

Draft-07 → Draft-2020-12

Draft-07 → Draft-2020-12

Smaller jump. Main changes:
  1. definitions
    $defs
    (and update
    $ref
    paths)
  2. Array-form
    items
    prefixItems
  3. additionalItems
    items
    (when
    prefixItems
    present)
  4. dependencies
    dependentRequired
    /
    dependentSchemas
  5. Consider adopting
    unevaluatedProperties
    /
    unevaluatedItems
    for stricter validation of combined schemas
跨度较小,主要变更:
  1. definitions
    $defs
    (同时更新
    $ref
    路径)
  2. 数组形式的
    items
    prefixItems
  3. additionalItems
    items
    (当存在
    prefixItems
    时)
  4. dependencies
    dependentRequired
    /
    dependentSchemas
  5. 考虑采用
    unevaluatedProperties
    /
    unevaluatedItems
    对组合schema进行更严格的校验

Draft-2019-09 → Draft-2020-12

Draft-2019-09 → Draft-2020-12

Minimal changes:
  1. Array-form
    items
    prefixItems
    ,
    additionalItems
    items
  2. $recursiveRef
    /
    $recursiveAnchor
    $dynamicRef
    /
    $dynamicAnchor
变更最少:
  1. 数组形式的
    items
    prefixItems
    additionalItems
    items
  2. $recursiveRef
    /
    $recursiveAnchor
    $dynamicRef
    /
    $dynamicAnchor

Verifying a migrated schema

验证已迁移的schema

After migration, validate the schema itself against the target draft's meta-schema:
typescript
import ZSchema from 'z-schema';

const validator = ZSchema.create({ version: 'draft2020-12' });

try {
  validator.validateSchema(migratedSchema);
  console.log('Schema is valid for draft-2020-12');
} catch (err) {
  console.log('Schema issues:', err.details);
}
Then test data validation to confirm behavior is unchanged:
typescript
// Test with known-good data
validator.validate(knownGoodData, migratedSchema);

// Test with known-bad data
const { valid } = validator.validateSafe(knownBadData, migratedSchema);
if (valid) {
  console.warn('Migration issue: previously invalid data now passes');
}
迁移完成后,对照目标草案的元schema验证schema本身:
typescript
import ZSchema from 'z-schema';

const validator = ZSchema.create({ version: 'draft2020-12' });

try {
  validator.validateSchema(migratedSchema);
  console.log('Schema is valid for draft-2020-12');
} catch (err) {
  console.log('Schema issues:', err.details);
}
然后测试数据校验,确认行为没有发生变化:
typescript
// 使用已知合法数据测试
validator.validate(knownGoodData, migratedSchema);

// 使用已知非法数据测试
const { valid } = validator.validateSafe(knownBadData, migratedSchema);
if (valid) {
  console.warn('迁移问题:此前非法的数据现在通过了校验');
}

Backward compatibility

向后兼容性

If schemas must work across multiple draft versions, use
version: 'none'
and set
$schema
in each schema to declare its own draft:
typescript
const validator = ZSchema.create({ version: 'none' });
如果schema需要跨多个草案版本使用,请设置
version: 'none'
,并在每个schema中设置
$schema
来声明自身的草案版本:
typescript
const validator = ZSchema.create({ version: 'none' });

Reference files

参考文件

  • references/keyword-mapping.md — Complete keyword mapping across all drafts with before/after examples
  • references/keyword-mapping.md — 覆盖所有草案版本的完整关键字映射,包含变更前后示例