blog
blog copied to clipboard
JSON Schema 全景漫游
site: https://tour.json-schema.org/ repo: https://github.com/json-schema-org/tour
01-Getting-Started
01-Your-First-Schema
{
"name": "John Doe",
"age": 25
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
}
}
02-Nesting-Objects
嵌套对象
{
"name": {
"firstName": "John",
"lastName": "Doe",
"middleName": "Smith"
}
"age": 25,
}
{
"type": "object",
"properties": {
"name": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"middleName": {
"type": "string"
}
}
},
"age": {
"type": "integer"
}
}
}
03-Required-Properties
{
"name": {
"firstName": "John",
"lastName": "Doe",
"middleName": "Smith"
}
"age": 25,
}
{
"type": "object",
"properties": {
"name": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"middleName": {
"type": "string"
}
},
"required": ["firstName", "lastName"]
},
"age": {
"type": "integer"
}
}
}
04-Enumerated-Values
{
"name": "John Doe",
"age": 25,
"hobbies": "reading"
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"hobbies": {
"type": "string",
"enum": ["reading", "writing", "painting"]
}
}
}
05-Arrays
{
"name": "John Doe",
"age": 25,
"hobbies": ["reading", "writing"]
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"hobbies": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["name", "age", "hobbies"]
}
06-Array-of-Objects
{
"name": "John Doe",
"age": 25,
"skills": [
{
"name": "JavaScript",
"level": "beginner"
},
{
"name": "React",
"level": "intermediate"
}
]
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"skills": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"level": { "type": "string" }
}
}
}
}
}
02-Primitive-Types
01-Constraining-String-Length
{
"name": "John Doe",
"age": 25,
"postalCode": "385004",
"phoneNumber": "84584898564"
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"phoneNumber": {
"type": "string",
"minLength": 10,
"maxLength": 10
},
"postalCode": {
"type": "string",
"minLength": 6,
"maxLength": 6
}
}
}
02-Regular-Expressions-in-Strings
{
"name": "John Doe",
"age": 25,
"postalCode": "385004",
"phoneNumber": "84584898564",
"countryCode": "IN"
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"postalCode": {
"type": "string",
"pattern": "^[0-9]{6}$"
},
"phoneNumber": {
"type": "string",
"pattern": "^[0-9]{10}$"
},
"countryCode": {
"type": "string",
"pattern": "^[A-Z]{2}$"
}
}
}
-
^
asserts the start of the string. -
[0-9]
matches any digit from 0 to 9. -
{6}
specifies that the previous pattern should be repeated exactly 6 times. -
$
asserts the end of the string.
03-Constraining-Number
{
"name": "John Doe ",
"age": 25,
"dateOfBirth": {
"day": 1,
"month": 1,
"year": 1995
}
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer",
"minimum": 18,
"maximum": 60
},
"dateOfBirth": {
"type": "object",
"properties": {
"year": {
"type": "integer",
"minimum": 1964,
"maximum": 2024
},
"month": {
"type": "integer",
"minimum": 1,
"maximum": 12
},
"day": {
"type": "integer",
"minimum": 1,
"maximum": 31
}
}
}
}
}
integer 表示整数类型
04-Exclusively-Constraining-Number
{
"name": "John Doe",
"age": 25,
"salary": 50000
}
- age should be greater than 18 and less than 60
- salary should be greater than 30000 and less than 80000
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer",
"exclusiveMinimum": 18,
"exclusiveMaximum": 60
},
"salary": {
"type": "integer",
"exclusiveMinimum": 30000,
"exclusiveMaximum": 80000
}
}
}
exclusiveMinimum
表示 x 大于某值,x > exclusiveMinimum
exclusiveMaximum
表示 x 小于某值,x < exclusiveMaximum
05-Multiple-of-a-Number
{
"name": "John Doe",
"age": 25,
"hourlyWage": 10
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"hourlyWage": {
"type": "number",
"multipleOf": 0.25,
"minimum": 0,
"maximum": 100
}
}
}
hourlyWage 是 0.25 的倍数,且 hourlyWage 最小值为 0 ,最大值为 100
06-Decimal-Numbers
{
"name": "John Doe",
"age": 25,
"performanceRating": 4.5
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"performanceRating": {
"type": "number",
"minimum": 0,
"maximum": 5
}
}
}
PerformanceRating 属性接受最小值为 0 、最大值为 5 的十进制数字, 可以是小数
07-Enumerated Values II
{
"name": "John Doe",
"age": 25,
"performanceRating": 4
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"performanceRating": {
"enum": [1, 2, 3, 4, 5, null]
}
}
}
以前,我们只对字符串使用枚举值。但是,您也可以将它们用于任何类型,包括数字和空值。
08-Defining-Constant-Values
{
"name": "John Doe",
"age": 25,
"companyName": "MyCompany"
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": { "type": "integer", "const": 25 },
"companyName": {
"const": "MyCompany"
}
}
}
- const 关键字用于为属性定义单个常量值。const 关键字的值可以是任何有效的 JSON 值。
companyName 是一个常量值
MyCompany
, age 为常量 25
09-Combining-Types
{
"name": "John Doe",
"age": 25,
"hasAgreedToTerms": true
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"hasAgreedToTerms": {
"type": ["boolean", "null"]
}
}
}
可以通过将类型数组传递给 type 字段来定义多个类型
hasAgreedToTerms 属性接受布尔值和空值
03-Objects
01-Pattern-Properties
{
"name": "John Doe",
"age": 25,
"DEPT-001": "HR"
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
},
"patternProperties": {
"^DEPT-[0-9]{3}$": {
"pattern": "^[A-Z]+$"
}
},
"additionalProperties": false
}
这就是 patternProperties 发挥作用的地方:它将正则表达式映射到模式。如果属性名与给定的正则表达式匹配,则属性值必须针对相应的模式进行验证。
提示: 使用
patternProperties
关键字定义属性名称的模式,使用pattern
关键字定义属性值的模式。您可以将模式设置为^[ A-Z ]+$
以匹配所有大写字母。
将
addtionalProperties
设置为 false 以禁止任何其他属性。我们将在下一课中学习更多关于附加属性的知识。
02-Additional-Properties
{
"type": "object",
"properties": {
"name": {...},
"age": {...}
},
"additionalProperties": false
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
},
"additionalProperties": {
"type": "integer"
}
}
默认情况下,允许任何附加属性。如果将 additionalProperties 设置为 false 可以禁止任何附加属性。
可以将 addtionalProperties 设置为一个 schema,以为其他属性定义 schema
03-Constraining-Number-of-Properties
{
"name": "John Doe",
"age": 25,
"contactMethods": {
"email": "[email protected]",
"phone": "1234567890",
"mobile": "0987654321"
}
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"contactMethods": {
"type": "object",
"minProperties": 2,
"maxProperties": 5,
"additionalProperties": {
"type": "string"
}
}
}
}
现在,将 minProperties 和 maxProperties 关键字添加到侧编辑器上的模式中,以设置 contactMethods 对象中属性的最小和最大数量。
此外,在 contactMethod 对象中,使用 addtionalProperties 关键字确保属性的值是字符串类型。
04-Applying-Schema-to-Property-Names
{
"type": "object",
"propertyNames": {
"pattern": "^[A-Z]+$"
}
}
-
对象应该至少有 2 个属性。
-
属性名称应以大写字母书写,并且长度应至少为 3 个字符。
-
属性值应该是字符串或整数。
{
"type": "object",
"minProperties": 2,
"propertyNames": {
"pattern": "^[A-Z]{3,}$"
},
"additionalProperties": {
"type": ["string", "integer"]
}
}
04-Arrays
01-Specifying-Length-of-an-Array
{
"name": "John Doe",
"age": 25,
"phones": ["123-456-7890", "987-654-3210"]
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"phones": {
"type": "array",
"items": {
"type": "string",
"pattern": "^\\d{3}-\\d{3}-\\d{4}$"
},
"minItems": 1,
"maxItems": 3
}
}
}
phones 属性,并将最小项指定为 1,最大项指定为 3。另外,将电话号码的格式限制为 xxx-xxx-xxxx。
提示:使用正则表达式
^\\d{3}-\\d{3}-\\d{4}$
和pattern
关键字来验证电话号码格式。
02-Unique-Items
{
"name": "John Doe",
"age": 25,
"phones": ["123-456-7890", "987-654-3210"]
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"phones": {
"type": "array",
"items": {
"type": "string",
"pattern": "^\\d{3}-\\d{3}-\\d{4}$"
},
"uniqueItems": true
}
}
}
03-Tuple-Validation
{
"name": "John Doe",
"age": 25,
"address": [123, "Main St", "Avenue", "NW"]
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"address": {
"type": "array",
"prefixItems": [
{ "type": "integer" },
{ "type": "string" },
{ "type": "string", "enum": ["Street", "Avenue", "Boulevard"] },
{ "type": "string", "enum": ["NW", "NE", "SE", "SW"] }
]
}
}
}
在这种情况下,可以使用 prefixItems 关键字为元组数组的每个元素定义模式。
Example
{
"type": "array",
"prefixItems": [{ "type": "integer" }, { "type": "string" }]
}
上面的模式定义了一个数组,其中第一个元素应该是整数,第二个元素应该是字符串。
04-Additional-Items-in-Tuples
{
"name": "John Doe",
"age": 25,
"address": [123, "Main St", "Avenue", "NW"]
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"address": {
"type": "array",
"items": {
"type": ["string"]
},
"prefixItems": [
{
"type": "number"
},
{
"type": "string"
},
{
"enum": ["Street", "Avenue", "Boulevard"]
},
{
"enum": ["NW", "NE", "SW", "SE"]
}
]
}
}
}
可以将 items 关键字设置为 false,以禁止在元组数组中添加其他项.
提示:向 items 关键字添加一个子 schame,以定义附加项的 schema。
05-Enumerated-Array-Items
{
"name": "John Doe",
"age": 25,
"relevantDepartments": ["HR", "Finance"]
}
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"relevantDepartments": {
"type": "array",
"items": {
"enum": ["HR", "Finance", "IT", "Admin"]
},
"uniqueItems": true
}
}
}
前面,我们使用 enum 来限制字符串属性的值。类似地,可以使用 enum 关键字限制数组项的值。
06-Ensuring-Array-Content-With-Contains
在下面的示例中,我们有一个验证数字数组的 JSON Schema。该模式确保数组至少包含一个小于 10 的元素。
{
"type": "array",
"contains": {
"type": "number",
"maximum": 10
}
}
现在,我们要确保 skills 数组至少包含一个等于“JavaScript”的元素。
提示:使用 const 关键字指定 JavaScript 作为必需的元素。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"skills": {
"type": "array",
"contains": {
"type": "string",
"const": "JavaScript"
}
}
},
"required": ["name", "age", "skills"]
}
07-minContains-and-maxContains
下面的示例演示了如何使用 minContains 和 maxContains 关键字来确保数组恰好包含 2 个小于 10 的元素。
{
"type": "array",
"contains": {
"type": "number",
"maximum": 10
},
"minContains": 2,
"maxContains": 2
}
我们的员工有工作时间。我们要确保 workedHours 数组至少包含两个大于或等于 8 且小于或等于 12 的元素。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"workedHours": {
"type": "array",
"contains": {
"type": "number",
"minimum": 8,
"maximum": 12
},
"minContains": 2
}
}
}
08-Unevaluated-Items
我们已经定义了带有 prefixItems 的数组项。当项目多于定义的 prefixItems 时,可以使用 unevaluatedItems 为其余项目定义子模式。
{
"type": "array",
"prefixItems": [{ "type": "number" }, { "type": "string" }],
"unevaluatedItems": { "type": "number" }
}
在这种情况下,前两个项由 prefixItems 计算,其余项由 unevaluatedItems 计算。
Task
-
前三个元素只能有“HTML”、“CSS”和“JavaScript”作为值(以任何顺序),不能有其他任何值。
-
其余元素为字符串类型。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"skills": {
"type": "array",
"prefixItems": [
{ "type": "string", "enum": ["HTML", "CSS", "JavaScript"] },
{ "type": "string", "enum": ["HTML", "CSS", "JavaScript"] },
{ "type": "string", "enum": ["HTML", "CSS", "JavaScript"] }
],
"unevaluatedItems": { "type": "string" }
}
}
}
05-Conditional-Validation
01-Ensuring-Conditional-Property-Presence
什么是条件验证?
条件验证涉及根据 JSON 文档中其他属性的存在与否应用验证规则。
例如:
-
dependentRequired
: 如果属性 a 存在,那么属性 B 必须存在。 -
dependentSchemas
: 如果存在属性 a,则应用子模式 B。 -
if-then-else
: 如果子模式 a 有效,则子模式 B 必须有效,否则子模式 C 必须有效。 -
implications
: 如果子模式 A 是有效的,那么子模式 B 一定是有效的。
{
"name": "John Doe",
"creditCardNumber": "1234 5678 1234 5678",
"address": "123 Main St"
}
Task
如果 creditCardNumber 属性存在,那么地址属性也必须存在。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"creditCardNumber": {
"type": "string"
},
"address": {
"type": "string"
}
},
"dependentRequired": {
"creditCardNumber": ["address"]
},
"required": ["name"]
}
02-Mutual Dependency
{
"name": "John Doe",
"creditCardNumber": "1234 5678 1234 5678",
"address": "123 Main St"
}
确保 creditCardNumber 和 address 是相互依赖的。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"creditCardNumber": {
"type": "string"
},
"address": {
"type": "string"
}
},
"dependentRequired": {
"creditCardNumber": ["address"],
"address": ["creditCardNumber"]
},
"required": ["name"]
}
03-Conditionally-Apply-a-Subschema
当你希望基于属性的存在与否应用 subschema 时,可以使用 dependentSchemas 关键字。此关键字允许您定义仅在存在或不存在特定属性时应用的 subschema。
Task
{
"name": "John Doe",
"creditCardNumber": "1234 5678 1234 5678",
"address": "123 Main St"
}
更新以确保如果存在 creditCardNumber 属性,那么使用 dependentSchemas 关键字也必须存在地址属性。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"creditCardNumber": {
"type": "string"
}
},
"dependentSchemas": {
"creditCardNumber": {
"properties": {
"address": {
"type": "string"
}
},
"required": ["address"]
}
},
"required": ["name"]
}
04-if-then-keyword
{
"name": "John Doe",
"isStudent": true,
"age": 25
}
如果 isStudent 为真,则年龄字段必须存在。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"isStudent": {
"type": "boolean"
}
},
"required": ["name"],
"if": {
"properties": {
"isStudent": {
"const": true
}
},
"required": ["isStudent"]
},
"then": {
"required": ["age"]
}
}
05-if-then-else
{
"name": "John Doe",
"isStudent": true,
"age": 25
}
如果 isStudent 为真,则必须显示年龄字段,否则必须显示年级字段。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"isStudent": {
"type": "boolean"
},
"grade": {
"type": "number",
"minimum": 0,
"maximum": 10
}
},
"if": {
"properties": { "isStudent": { "const": true } },
"required": ["isStudent"]
},
"then": { "required": ["age"] },
"else": { "required": ["grade"] },
"required": ["name", "isStudent"]
}
06-Combining-Subschemas
01-Reusing-and-Referencing-with-defs-and-ref
组合子模式
在本模块中,您将学习如何组合多个子模式来创建更复杂的 JSON 模式。您将学习以下关键字:allOf、anyOf、oneOf、not、$defs、$ref 和递归模式。
在 JSON Schema 中,$defs关键字允许您定义可重用的子模式。然后可以使用$ref 关键字引用这些子模式。
要用$defs
定义一个子模式,你可以使用以下语法:
{
"$defs": {
"mySubschema": {
"type": "string",
"maxLength": 10
}
}
}
在上面的例子中,我们定义了一个名为 mySubschema 的子模式,它指定该值应该是一个最大长度为 10 个字符的字符串。
要使用$ref
来引用这个子模式,你可以使用以下语法:
{
"$ref": "#/$defs/mySubschema"
}
在上面的例子中,我们使用$ref
来引用 mySubschema 子模式。这允许我们在需要时重用 mySubschema
的定义。
通过促进代码重用,使用$defs
和$ref
可以帮助您的 JSON 模式更加模块化和可维护。
Task
{
"name": {
"firstName": "John",
"middleName": "Smith",
"lastName": "Doe"
}
}
在 schame 中定义名为 stringType 的子模式,它只是“type”:“string”
,然后使用$ref
引用属性 firstName, middleName 和 lastName
{
"$defs": {
"stringType": {
"type": "string"
}
},
"type": "object",
"properties": {
"name": {
"type": "object",
"properties": {
"firstName": {
"$ref": "#/$defs/stringType"
},
"middleName": {
"$ref": "#/$defs/stringType"
},
"lastName": {
"$ref": "#/$defs/stringType"
}
}
}
},
"required": ["name"]
}
02-id-and-schema
$schema
在 JSON Schema 中, $schema
是一个字符串,定义了写入该 schema 的 JSON Schema 标准的版本。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
}
在上面的示例中,架构是在 JSON Schema 草案 2020-12 中编写的。您可以在此处找到最新版本的 JSON Schema。
在本教程中,我们使用了 JSON Schema 草案 2020-12。
$id
$id
关键字是一个字符串,用于定义模式的 URI。
{
"$id": "https://example.com/person",
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
在上面的示例中,模式的 URI 为https://example.com/person
。
模式 URI 可用于使用 $ref
关键字从其他模式引用该模式。
{
"$ref": "https://example.com/person"
}
Task
我们定义了一个简单的模式,如下所示。
{
"$id": "https://example.com/string",
"type": "string"
}
在 schema 中使用 $ref
关键字在 name 属性中引用此模式。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"$ref": "https://example.com/string"
},
"age": {
"type": "integer"
}
}
}
03-Valid-Against-allOf-the-Subschemas(AND)
对所有子 schema(AND)有效
当您希望确保一个实例对所有子模式都有效时,可以使用 allOf 关键字。
您可以将 allOf
视为子模式之间的 AND 操作。如果其中一个子模式失败,则认为该实例无效。
{
"name": "John Doe"
}
我们将创建两个子模式 1. minStringLength
和 2. 字母和数字
,然后使用 name 属性中的 allOf 将它们组合起来。
{
"$defs": {
"minStringLength": { "minLength": 5 },
"alphaNumeric": { "pattern": "^[a-zA-Z0-9]*$" }
},
"type": "object",
"properties": {
"name": {
"type": "string",
"allOf": [
{ "$ref": "#/$defs/minStringLength" },
{ "$ref": "#/$defs/alphaNumeric" }
]
}
}
}
上面的模式确保 name 属性对 minStringLength 和 alphannumeric 子模式都有效。换句话说,name 属性的最小长度必须为 5 个字符,并且必须只包含字母数字字符。
注意:没有必要使用
$defs
和$ref
来定义子 schame。您也可以直接内联地定义子 schema。
Task
定义一个内联子模式,检查 age 是否为整数类型
使用 age 属性中的 allOf 组合 ageLimit 和内联子模式。
{
"$defs": {
"ageLimit": {
"minimum": 18,
"maximum": 60
}
},
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"allOf": [
{
"type": "integer"
},
{
"$ref": "#/$defs/ageLimit"
}
]
}
},
"required": ["name"]
}
04-Valid-Against-oneOf-the-Subschemas(XOR)
验证对其中一个子 schema 有效
Example
{
"name": "John Doe",
"age": 25,
"dateOfBirth": "1999-01-01"
}
让我们向 JSON 文档添加一个新的属性 dateOfBirth:
现在要在文档中应用这些条件:
- 如果存在年龄,则不应存在出生日期,反之亦然。
- 年龄和出生日期不应同时出现。
- 如果它们都不存在,那么该文档应该是无效的。
{
"type": "object",
"properties": {
...
"dateOfBirth": { "type": "string", "format": "date" }
},
"oneOf": [
{ "required": ["age"] },
{ "required": ["dateOfBirth"] }
]
}
Task
{
"name": "John Doe",
"age": 25
}
在侧面编辑器中为上面的 JSON 文档提供了一个模式。使用 oneOf 关键字,更新模式以确保年龄符合以下条件之一:
- 年龄介乎 18 至 60 岁(包括在内) ,或,
- 大于 65(含)。
提示: 使用最小 (minimum) 和最大关键字 (maximum) 来定义范围。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer",
"oneOf": [{ "minimum": 18, "maximum": 60 }, { "minimum": 65 }]
}
}
}
05-Valid-Against-anyOf-the-Subschemas(OR)
对任何子模式有效 (OR)
anyOf
关键字用于定义多个子模式。如果该实例对于任一子模式有效,则该文档被视为有效。
Example
{
"name": "John Doe",
"age": 25,
"dateOfBirth": "1995-12-17"
}
我们希望在文档中允许使用“age”和“dateOfBirth”属性。如果文档具有 Age 或 dateOfBirth 属性,则该文档有效。我们可以使用 anyOf 关键字来定义这个条件。
{
"type": "object",
"properties": {...},
"anyOf": [
{"required": ["age"]},
{"required": ["dateOfBirth"]}
]
}
Task
{
"name": "John Doe",
"employeeType": "full-time",
"salary": 50000,
"hourlyRate": 25
}
要求:
- 它具有 salary 或 hourlyRate 属性。
- 它具有 salary 和 hourlyRate 属性。
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"employeeType": {
"enum": ["full-time", "part-time"]
}
},
"anyOf": [
{
"required": ["salary"]
},
{
"required": ["hourlyRate"]
}
]
}
06-inverting-validation-with-not
反向验证
not
关键字用于反转验证。如果实例对于子模式无效,则该文档被视为有效。
{
"name": "John Doe",
"age": 25
}
我们希望年龄大于或等于 18 岁。但不应该是 21 岁。我们可以使用 not 关键字来定义此条件。
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": {
"type": "integer",
"minimum": 18,
"not": { "const": 21 }
}
}
}
Task
{
"name": "John Doe",
"age": 21,
"status": "active"
}
要求:
- status 不能为 null
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"status": {
"not": {
"type": "null"
}
}
}
}
07-Recursive-Schemas
递归架构
在 JSON 模式中,递归模式允许定义引用自身的模式。这在处理分层数据结构或建模递归关系时非常有用。
{
"name": "John Doe",
"links": [
{
"name": "Jane Doe",
"links": [
{
"name": "Alice Doe",
"links": []
}
]
},
{
"name": "Jack Doe",
"links": []
}
]
}
要定义递归模式,可以使用 $ref 关键字引用模式本身:
{
"$defs": {
"TreeNode": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"children": { "$ref": "#/$defs/TreeNode" }
},
"required": ["name", "children"]
}
}
},
"$ref": "#/$defs/TreeNode"
}
在上面的示例中,TreeNode 架构在 children 属性中引用自己,从而创建一个递归结构。
Task
{
"name": "John Doe",
"next": {
"value": "Jane Doe",
"next": {
"value": "Alice Doe",
"next": {}
}
}
}
使用递归模式定义 next schema:
- 在 $defs 内部定义一个子模式,接下来引用它自己并将 null 作为基本情况。
- 您将在 $defs/next 模式中定义 next 属性。next property 的值可以是 null,也可以是下一个模式本身。您可以使用 anyOf 关键字来定义多个模式。
{
"$defs": {
"next": {
"type": "object",
"properties": {
"value": {
"type": ["string"]
},
"next": {
"oneOf": [
{
"$ref": "#/$defs/next"
},
{
"type": "null"
}
]
}
},
"required": ["next", "value"]
}
},
"type": "object",
"properties": {
"name": {
"type": "string"
},
"next": {
"$ref": "#/$defs/next"
}
}
}
07-Miscellaneous
01-Extending-Closed-Schemas-with-unevaluatedProperties
扩展封闭的 schame
在前面的 Objects 模块中,我们学习了 addtionalProperties。但是,需要注意的是,addtionalProperties 只能识别在同一个子模式中声明的属性。
因此,addtionalProperties 可以限制您使用组合关键字(如 allOf)“扩展”模式。在下面的示例中,我们可以看到 addtionalProperties 如何导致扩展地址架构示例的尝试失败。
{
"allOf": [
{
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"],
"additionalProperties": false
}
],
"properties": {
"type": { "enum": ["residential", "business"] }
},
"required": ["type"]
}
上述架构不允许您定义类型属性。因为 addtionalProperties 被设置为 false。原因是,addtionalProperties 只能识别在同一个子模式中声明的属性。
Unevaluated Properties
我们在 addtionalProperties 中看到的挑战可以使用 unevaluatedProperties 关键字来解决。此关键字允许您定义不由当前架构计算的属性。
{
"allOf": [
{
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
],
"properties": {
"type": { "enum": ["residential", "business"] }
},
"unevaluatedProperties": false,
"required": ["type"]
}
Task
将 unevaluatedProperties 添加到架构中,以允许将数字 number
作为附加属性。
{
"allOf": [
{
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": ["street_address", "city", "state"]
}
],
"properties": {
"type": {
"enum": ["residential", "business"]
}
},
"required": ["type"],
"unevaluatedProperties": {
"type": "number"
}
}
08-Annotating-JSON-Schemas
01-Title-and-Description
title 和 description 关键字用于提供人类可读的模式标题和描述。
这些关键字不用于验证,但工具和软件可以使用它们来提供关于模式的更多信息。
{
"type": "object",
"title": "Person",
"description": "A person in the system",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
}
}
02-deprecated-readOnly-and-writeOnly
-
deprecated
弃用关键字是一个布尔值,表示该关键字应用的实例值不应该被使用,将来可能会被删除。
布尔关键字 readOnly 和 writeOnly 通常用于 API 上下文中。
-
readOnly
表示该值不能修改。它可以用来指示更改值的 PUT 请求将导致 400 Bad request 响应。 -
writeOnly
表示可以设置一个值,但将保持隐藏。它可用于指示您可以使用 PUT 请求设置一个值,但在使用 GET 请求检索该记录时不会包含它。
Task
- 向 schema 添加
deprecated
弃用关键字。 - 将 schema 中的 readOnly 添加到 name 属性中
- 向 age 属性添加 writeOnly。
{
"type": "object",
"properties": {
"name": {
"type": "string",
"readOnly": true
},
"age": {
"type": "integer",
"writeOnly": true
}
},
"deprecated": true
}
03-comment-and-default
要在 JSON Schema 中添加注释,请使用$comment关键字。$comment
关键字是一个字符串,它提供了关于模式的附加信息
可以使用 default
关键字为属性设置默认值。default 关键字用于为属性提供默认值。
{
"type": "object",
"properties": {
"name": {
"type": "string",
"$comment": "This is the name of the employee"
},
"age": {
"type": "integer",
"default": 18
}
}
}