处理复杂的结构化数据时,需要确定数据是否有效。 JSON-Schema是JSON文档的标准,描述了JSON数据的结构和要求。 在这个由两部分组成的系列文章中,您将学习如何使用JSON-Schema来验证数据。
假设您有一个用户数据库,其中每个记录看起来都类似于此示例:
{
"id": 64209690,
"name": "Jane Smith",
"email": "jane.smith@gmail.com",
"phone": "07777 888 999",
"address": {
"street": "Flat 1, 188 High Street Kensington",
"postcode": "W8 5AA",
"city": "London",
"country": "United Kingdom"
},
"personal": {
"DOB": "1982-08-16",
"age": 33,
"gender": "female"
},
"connections": [
{
"id": "35434004285760",
"name": "John Doe",
"connType": "friend",
"since": "2014-03-25"
},
{
"id": 13418315,
"name": "James Smith",
"connType": "relative",
"relation": "husband",
"since": "2012-07-03"
}
],
"feeds": {
"news": true,
"sport": true,
"fashion": false
},
"createdAt": "2015-09-22T10:30:06.000Z"
}我们要处理的问题是如何确定上述记录是否有效。
示例非常有用,但在描述数据要求时还不够。 JSON-Schema可以解决。 这是描述用户记录的可能模式之一:
{
"$schema": "https://json-schema.org/draft-04/schema#",
"id": "http://mynet.com/schemas/user.json#",
"title": "User",
"description": "User profile with connections",
"type": "object",
"properties": {
"id": {
"description": "positive integer or string of digits",
"type": ["string", "integer"],
"pattern": "^[1-9][0-9]*$",
"minimum": 1
},
"name": { "type": "string", "maxLength": 128 },
"email": { "type": "string", "format": "email" },
"phone": { "type": "string", "pattern": "^[0-9()\-\.\s]+$" },
"address": {
"type": "object",
"additionalProperties": { "type": "string" },
"maxProperties": 6,
"required": ["street", "postcode", "city", "country"]
},
"personal": {
"type": "object",
"properties": {
"DOB": { "type": "string", "format": "date" },
"age": { "type": "integer", "minimum": 13 },
"gender": { "enum": ["female", "male"] }
}
"required": ["DOB", "age"],
"additionalProperties": false
},
"connections": {
"type": "array",
"maxItems": 150,
"items": {
"title": "Connection",
"description": "User connection schema",
"type": "object",
"properties": {
"id": {
"type": ["string", "integer"],
"pattern": "^[1-9][0-9]*$",
"minimum": 1
},
"name": { "type": "string", "maxLength": 128 },
"since": { "type": "string", "format": "date" },
"connType": { "type": "string" },
"relation": {},
"close": {}
},
"oneOf": [
{
"properties": {
"connType": { "enum": ["relative"] },
"relation": { "type": "string" }
},
"dependencies": {
"relation": ["close"]
}
},
{
"properties": {
"connType": { "enum": ["friend", "colleague", "other"] },
"relation": { "not": {} },
"close": { "not": {} }
}
}
],
"required": ["id", "name", "since", "connType"],
"additionalProperties": false
}
},
"feeds": {
"title": "feeds",
"description": "Feeds user subscribes to",
"type": "object",
"patternProperties": {
"^[A-Za-z]+$": { "type": "boolean" }
},
"additionalProperties": false
},
"createdAt": { "type": "string", "format": "date-time" }
}
}查看上面的架构及其描述的用户记录(根据该架构有效)。 这里有很多解释要做。
用于根据模式验证用户记录JavaScript代码可以是:
var Ajv = require('ajv');
var ajv = Ajv({allErrors: true});
var valid = ajv.validate(userSchema, userData);
if (valid) {
console.log('User data is valid');
} else {
console.log('User data is INVALID!');
console.log(ajv.errors);
}或为了获得更好的性能:
var validate = ajv.compile(userSchema);
var valid = validate(userData);
if (!valid) console.log(validate.errors);GitHub repo tutsplus-json-schema中提供了所有代码示例。 您也可以在浏览器中尝试一下 。
示例中使用的验证器Ajv是JavaScript最快的JSON-Schema验证器。 我创建了它,因此在本教程中将使用它。
在继续之前,让我们快速处理所有原因。
为什么要单独验证数据?
- 快速失败
- 避免数据损坏
- 简化处理代码
- 在测试中使用验证码
为什么要使用JSON(而不是XML)?
- 与XML一样广泛
- 比XML更容易处理和更简洁
- 由于JavaScript主导了Web开发
为什么要使用架构?
- 陈述式
- 易于维护
- 可以被非编码者理解
- 无需编写代码,可以使用第三方开源库
为什么要使用JSON模式?
- 在所有JSON验证标准中采用最广泛
- 非常成熟(当前版本为4,对于版本5有建议)
- 涵盖验证场景的很大一部分
- 使用易于解析的JSON文档进行模式
- 平台无关
- 容易扩展
- 30种以上用于不同语言的验证器,其中10种以上用于JavaScript,因此无需自己编写代码
任务
本教程包括几个相对简单的任务,以帮助您更好地了解JSON模式以及如何使用它。 有简单JavaScript脚本可以检查您是否正确完成了脚本。 要运行它们,您将需要安装node.js(您不需要任何经验)。 只需安装nvm (节点版本管理器)和最新的node.js版本:
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash
nvm install 4您还需要克隆存储库并运行npm install (它将安装Ajv验证程序)。
让我们深入了解模式!
JSON模式始终是一个对象。 它的属性称为“关键字”。 其中一些描述数据的规则(例如,“类型”和“属性”),一些描述模式本身(“ $ schema”,“ id”,“ title”,“ description”),我们将介绍他们以后。
如果数据根据该模式中的所有关键字均有效,则根据该模式是有效的-这确实很简单。
资料属性
因为大多数JSON数据由具有多个属性的对象组成,所以关键字“ properties”可能是最常用的关键字。 它仅适用于对象(有关“应用”的含义,请参见下一节)。
在上面的示例中,您可能已经注意到, “ properties”关键字内的每个属性都描述了数据中的相应属性。
每个属性的值本身就是JSON模式-JSON模式是一种递归标准。 数据中的每个属性都应根据“ properties”关键字中的相应架构有效。
这里重要的是, “ properties”关键字不需要任何属性。 它仅定义数据中存在的属性的模式。
例如,如果我们的模式是:
{
"properties": {
"foo": { "type": "string" }
}
}那么根据此模式,具有或不具有属性“ foo”的对象都可以有效:
{foo: "bar"}, {foo: "bar", baz: 1}, {baz: 1}, {} // all valid并且只有属性foo不是字符串的对象才是无效的:
{ foo: 1 } // invalid数据类型
您已经弄清楚了关键字“ type”的作用。 它可能是最重要的关键字。 它的值(字符串或字符串数组)定义数据必须有效的类型。
如上例所示,用户数据必须是一个对象。
大多数关键字适用于某些数据类型,例如,关键字“属性”仅适用于对象,关键字“模式”仅适用于字符串。
“应用”是什么意思? 假设我们有一个非常简单的架构:
{ "pattern": "^[0-9]+$" }您可能希望根据这样的模式有效,数据必须是与模式匹配的字符串:
"12345"但是JSON模式的标准规定,如果某个关键字不适用于该数据类型,则根据该关键字数据是有效的。 这意味着根据上面的模式(数字,数组,对象,布尔值,甚至为null),任何非“字符串”类型的数据均有效。 如果只希望与模式匹配的字符串有效,则架构应为:
{
"type": "string",
"pattern": "^[0-9]+$"
}因此,您可以创建非常灵活的架构来验证多种数据类型。
在用户示例中查看属性“ id”。 根据以下架构,它应该是有效的:
{
"type": ["string", "integer"],
"pattern": "^[1-9][0-9]*$",
"minimum": 1
}此架构要求有效的数据应该是“字符串”或“整数” 。 还有关键字“ pattern”仅适用于字符串。 它要求字符串应仅由数字组成,而不应从0开头。关键字“ minimum”仅适用于数字; 它要求该数字不少于1。
表达相同要求的另一种更为冗长的方法是:
{
"anyOf": [
{ "type": "string", "pattern": "^[1-9][0-9]*$" },
{ "type": "integer", "minimum": 1 },
]
}但是由于定义了JSON模式,该模式与第一个模式等效,在大多数验证程序中,该模式更短,更快。
可以在模式中使用的数据类型是“对象” , “数组” , “数字” , “整数” , “字符串” , “布尔”和“空” 。 请注意, “数字”包括“整数”,所有整数也都是数字。
号码验证
有几个关键字可以验证数字。 本节中的所有关键字仅适用于数字(包括整数)。
“最小”和“最大”是不言自明的。 除它们之外,还有关键字“ exclusiveMinimum”和“ exclusiveMaximum” 。 在我们的用户示例中,用户年龄必须是13或更大的整数。 如果用户年龄的架构为:
{
"type": "integer",
"minimum": 13,
"exclusiveMinimum": true
}那么此架构将要求用户年龄严格大于13,即允许的最低年龄为14。
验证数字的另一个关键字是“ multipleOf” 。 它的名称也说明了它的作用,您可以查看JSON-schema关键字参考以了解其工作原理。
字符串验证
还有几个关键字可以验证字符串。 本节中的所有关键字仅适用于字符串。
“ maxLength”和“ minLength”要求字符串不长于或短于给定的数字。 JSON模式的标准要求将unicode对(例如emoji字符)计为单个字符。 当您访问字符串的.length属性时,JavaScript会将其视为两个字符。
一些验证器根据标准要求确定字符串长度,而另一些验证器以JavaScript方式执行,这更快。 Ajv允许您指定如何确定字符串长度,默认设置是符合标准。
var schema = { "maxLength": 2 };
var ajv = Ajv(); // count unicode pairs as one character
ajv.validate(schema, "??"); // true
ajv.validate(schema, "??!"); // false
var ajv = Ajv({unicode: false}); // count unicode pairs as two characters
ajv.validate(schema, "?"); // true
ajv.validate(schema, "?!"); // false您已经在使用“ pattern”关键字了,它只需要数据字符串与根据JavaScript中使用的相同标准定义的正则表达式匹配即可。 有关架构和匹配的正则表达式,请参见下面的示例:
{"pattern": "^[1-9][0-9]*$" }; /^[1-9][0-9]*$/; // id
{"pattern": "^[A-Za-z]+$" }; /^[a-z]+$/i; // letters
{"pattern": "^[0-9()\-\.\s]+$"}; /^[0-9()\-\.\s]+$/; // phone“ format”关键字定义字符串的语义验证,例如在用户示例中为“ email” , “ date”或“ date-time” 。 JSON-Schema还定义了格式“ uri” , “主机名” , “ ipv4”和“ ipv6” 。 验证器以不同的方式定义格式,以优化验证速度或正确性。 Ajv给您一个选择:
var ajv = Ajv(); // "fast" format validation
ajv.validate({"format": "date"}, "2015-12-24"); // true
ajv.validate({"format": "date"}, "2015-14-33"); // true
var ajv = Ajv({format: 'full'); // more thorough format validation
ajv.validate({"format": "date"}, "2015-12-24"); // true
ajv.validate({"format": "date"}, "2015-14-33"); // false大多数验证器允许您将自定义格式定义为正则表达式或验证函数。 我们可以为我们的模式定义一个自定义格式“ phone” ,以便在多个地方使用它:
ajv.addFormat('phone', /^[0-9()\-\.\s]+$/);然后phone属性的架构为:
{ "type": "string", "format": "phone" }任务1
创建一个架构,该架构将要求数据为日期(字符串)或年份(数字),并且年份大于或等于1976。
将答案放在文件part1/task1/date_schema.json然后运行node part1/task1/validate进行检查。
对象验证
除了“属性”之外 ,您还可以在我们的用户示例中看到适用于对象的其他几个关键字。
“ required”关键字列出了对象中必须存在的属性才能使其有效。 您还记得, “ properties”关键字不需要属性,它仅在存在属性时对其进行验证。 “必需”是“属性 ”的补充,使您可以定义哪些属性是必需的,哪些是可选的。
如果我们有这个模式:
{
"properties": {
"foo": { "type": "string" }
},
"required": ["foo"]
}那么所有没有属性foo对象都将无效。
请注意,此架构仍然不需要将我们的数据作为对象-所有其他数据类型根据它都是有效的。 要要求我们的数据是一个对象,我们必须在其中添加“ type”关键字。
关键字“ patternProperties”允许您定义模式,如果属性名称与正则表达式匹配,则数据属性值应根据该模式有效。 可以在同一模式中将其与“ properties”关键字结合使用。
根据以下模式,用户示例中的feeds属性应该有效:
{
"type": "object",
"patternProperties": {
"^[A-Za-z]+$": { "type": "boolean" }
},
"additionalProperties": false
}为了有效, feeds应该是一个对象,该对象的名称仅由拉丁字母组成,并且其值为布尔值。
关键字“ additionalProperties”允许您根据所有其他关键字(未在“属性”中使用且与“ patternProperties”不匹配” )有效的方式来定义架构,或者完全禁止其他属性,如在feeds属性中所做的那样上面的模式。
在以下示例中, “ additionalProperties”用于为特定范围内的整数哈希创建简单的架构:
var schema = {
"type": "object",
"additionalProperties" {
"type": "integer",
"minimum": 0,
"maximum": 65535
}
};
var validate = ajv.compile(schema);
validate({a:1,b:10,c:100}); // true
validate({d:1,e:10,f:100000}); // false
validate({g:1,h:10,i:10.5}); // false
validate({j:1,k:10,l:'abc'}); // false使用“ maxProperties”和“ minProperties”关键字可以限制对象中的属性数量。 在我们的用户示例中, address属性的架构为:
{
"type": "object",
"additionalProperties": { "type": "string" },
"maxProperties": 6,
"required": ["street", "postcode", "city", "country"]
}此架构要求地址是具有必需属性street , postcode , city和country ,允许两个附加属性(“ maxProperties”为6),并且要求所有属性均为字符串。
“依赖项”可能是最复杂,最令人困惑且使用最罕见的关键字,但同时又是一个非常强大的关键字。 它允许您定义数据具有某些属性时应满足的要求。
对对象的这种要求有两种类型:具有其他一些属性(称为“属性依赖性”)或满足某种模式(“模式依赖性”)。
在我们的用户示例中,用户连接应针对的可能模式之一是:
{
"properties": {
"connType": { "enum": ["relative"] },
"relation": { "type": "string" }
},
"dependencies": {
"relation": ["close"]
}
}它要求connType属性等于“相对”(见下面的“枚举”关键字),并且如果该relation属性存在时,它是一个字符串。
它不要求存在relation ,但是“ dependencies”关键字要求如果存在relation属性,则也应该存在close属性。
尽管从示例中我们可以看到它可能必须为布尔值,但是在我们的模式中没有为close属性定义验证规则。 我们可以纠正此遗漏的方法之一是将“ dependencies”关键字更改为使用“ schemadependent”:
"dependencies": {
"relation": {
"properties": {
"close": { "type": "boolean" },
},
"required": ["close"]
}
}请注意, “ dependencies”关键字中“ relation”属性中的模式用于验证父对象(即连接),而不是数据中的relation属性的值。
任务2
您的数据库包含人员和机器。 仅使用到目前为止已经解释过的关键字创建一个架构来验证它们。 样本人类对象:
{
"human": true,
"name": "Jane",
"gender": "female",
"DOB": "1985-08-12"
}样本机器对象:
{
"model": "TX1000",
"made": "2013-08-29"
}请注意,它应该是同时验证人和机器的一种模式,而不是两种模式。
将答案放入文件part1/task2/human_machine_schema.json然后运行node part1/task2/validate进行检查。
提示:使用“ dependencies”关键字,然后在文件part1/task2/invalid.json查找哪些对象应该无效。
哪些对象可能也应该无效,也不在invalid.json文件中?
此任务的主要收获是,验证的目的不仅仅是验证所有有效对象是否有效。 我已经多次听到这种说法:“此架构将我的有效数据验证为有效,因此是正确的。” 该参数是错误的,因为您不需要做太多的事情就可以实现—空模式可以完成任务,因为它可以验证任何数据是否有效。
我认为验证的主要目的是将无效数据验证为无效数据,这就是所有复杂性的来源。
阵列验证
有几个关键字可以验证数组(它们仅适用于数组)。
“ maxItems”和“ minItems”要求数组的项目数不超过(或不少于)。 在用户示例中,该架构要求连接数不超过150。
“ items”关键字定义了一个(或多个)模式,项目应根据该模式有效。 如果此关键字的值是一个对象(如用户示例中所示),则此对象是一个模式,根据该模式数据应该有效。
如果“ items”关键字的值是一个数组,则此数组包含相应的项目应根据其有效的架构:
{
"type": "array",
"items": [
{ "type": "integer" },
{ "type": "string" }
]
}上面简单示例中的模式要求数据是数组,第一项是整数,第二项是字符串。
那两个之后的项目呢? 上面的架构没有定义其他项目的要求。 可以使用“ additionalItems”关键字定义它们。
“ additionalItems”关键字仅适用于“ items”关键字是数组且数据中的项目比“ items”关键字多的情况。 在所有其他情况下(没有“ items”关键字,它是一个对象,或者数据中没有更多的项目), “ additionalItems”关键字将被忽略,无论其值如何。
如果“ additionalItems”关键字为true,则将其忽略。 如果为假,并且数据中的项目多于“ items”关键字,则验证失败:
var schema = {
"type": "array",
"items": [
{ "type": "integer" },
{ "type": "string" }
],
"additionalItems": false
};
var validate = ajv.compile(schema);
console.log(validate([1, "foo", 3])); // false如果关键字“ additionalItems”是一个对象,则此对象是一个架构,根据该架构,所有其他项均应有效:
var schema = {
"type": "array",
"items": [
{ "type": "integer" },
{ "type": "string" }
],
"additionalItems": { "type": "integer" }
};
var validate = ajv.compile(schema);
console.log(validate([1, "foo", 3])); // true
console.log(validate([1, "foo", 3, 4])); // true
console.log(validate([1, "foo", "bar"])); // false请尝试这些示例,以了解“项目”和“ additionalItems”的工作方式。
适用于数组的最后一个关键字是“ uniqueItems” 。 如果其值为true ,则仅要求数组中的所有项目都不同。
验证关键字“ uniqueItems”在计算上可能是昂贵的,因此某些验证器选择不实施或仅部分实施。
Ajv可以选择忽略此关键字:
var schema = {
"type": "array",
"uniqueItems": true
};
var ajv = Ajv(); // validate uniqueItems
ajv.validate(schema, [1, 2, 3]); // true
ajv.validate(schema, [1, 2, 2]); // false
var ajv = Ajv({uniqueItems: false}); // ignore uniqueItems
ajv.validate(schema, [1, 2, 3]); // true
ajv.validate(schema, [1, 2, 2]); // true任务3
在JavaScript中创建日期对象的一种方法是将2到7个数字传递给Date构造函数:
var date = new Date(2015, 2, 15); // Sun Mar 15 2015 00:00:00 GMT+0000, month is 0 based
var date2 = new Date(year, month0, day, hour, minute, seconds, ms);您有一个数组。 创建一个架构,该架构将验证这是Date构造函数的有效参数列表。
将您的答案放在文件part1/task3/date_args_schema.json然后运行node part1/task3/validate进行检查。
“枚举”关键字
“ enum”关键字要求数据等于多个值之一。 它适用于所有类型的数据。
在用户示例中,它用于将personal财产内的gender财产定义为“男性”或“女性”。 它还用于在用户连接中定义connType属性。
尽管不是很普遍, “ enum”关键字可以与任何类型的值一起使用,不仅可以用于字符串和数字。
也可以用来要求数据等于特定值,如用户示例中所示:
"properties": {
"connType": { "enum": ["relative"] },
...
}JSON-Schema标准的下一版本 (v5) 的建议包括关键字“ constant”以执行相同的操作。
Ajv允许您使用v5中的“ constant”和其他一些关键字:
var schema = {
"constant": "relative"
};
var ajv = Ajv({v5: true}); // this options enables v5 keywords
var validate = ajv.compile(schema);
validate("relative"); // true
validate("other"); // false复合验证关键字
有几个关键字使您可以定义涉及针对多个模式进行验证的高级逻辑。 本节中的所有关键字均适用于所有数据类型。
我们的用户示例使用“ oneOf”关键字来定义对用户连接的要求。 如果数据成功针对数组内的一个模式成功验证,则此关键字有效。
如果数据根据“ oneOf”关键字中的所有模式无效,或者根据两个或多个模式有效,则该数据无效。
让我们更仔细地看一下我们的示例:
{
...
"oneOf": [
{
"properties": {
"connType": { "enum": ["relative"] },
"relation": { "type": "string" }
},
"dependencies": {
"relation": ["close"]
}
},
{
"properties": {
"connType": { "enum": ["friend", "colleague", "other"] },
"relation": { "not": {} },
"close": { "not": {} }
}
}
],
...
}上面的模式要求用户连接要么是“相对的”( connType属性),在这种情况下,它可能具有“ relation (字符串)和“ close (布尔值)属性,或者是“朋友”,“同事”或“其他”类型之一(在这种情况下,它一定不能具有属性relation和close )。
这些用于用户连接的模式是互斥的,因为没有数据可以同时满足这两个条件。 因此,如果连接有效且类型为“相对”,则没有必要根据第二个模式对其进行验证-连接将始终无效。 但是,任何验证器都将始终根据两种模式验证数据,以确保仅根据一种模式有效。
还有另一个关键字可以避免: “ anyOf” 。 此关键字仅要求数据根据数组中的某些模式(可能对几种模式)有效。
在上述情况下,架构是互斥的,并且根据一个以上的架构,没有任何数据可以有效,因此最好使用“ anyOf”关键字-在大多数情况下(除了其中的一种),它的验证速度更快。数据根据最后一个模式有效)。
在“ anyOf”表现出色的情况下使用“ oneOf”是一个非常常见的错误,会对验证性能产生负面影响。
我们的用户示例还将受益于将“ oneOf”替换为“ anyOf” 。
但是,在某些情况下,当我们确实需要“ oneOf”关键字时:
{
"type": "string",
"oneOf": [
{ "pattern": "apple" }
{ "pattern": "orange" }
]
}上面的模式将成功地验证提到橙子或苹果的字符串,但不能同时验证两种字符串(并且确实存在可以同时提及这两种字符串)。 如果这是您需要的,则需要使用“ oneOf” 。
与布尔运算符相比, “ anyOf”就像布尔OR, “ oneOf”就像XOR(异或)。 JavaScript(和许多其他语言)没有为“异或”定义运算符的事实表明,很少需要它。
还有关键字“ allOf” 。 它要求数据根据数组中的所有模式都是有效的:
{
"allOf": [
{ "$ref": "http://mynet.com/schemas/feed.json#" },
{ "maxProperties": 5 }
]
}“ $ ref”关键字允许您根据另一个文件(或文件的某些部分)中的架构要求数据有效。 我们将在本教程的第二部分中进行研究。
另一个错误是在模式中的“ oneOf” , “ anyOf”和“ allOf”关键字中添加了绝对必要的内容。 例如,在我们的用户示例中,我们可以将连接应满足的所有要求放入“ anyOf”中 。
我们也可能不必要地使苹果和橙子的例子变得复杂:
{
"oneOf": [
{ "type": "string", "pattern": "apple" }
{ "type": "string", "pattern": "orange" }
]
}另一个“逻辑”关键字是“ not” 。 它要求根据该关键字的值的模式,数据无效。
例如:
{
"type": "string",
"not": {
"pattern": "apple"
}
}上面的模式将要求数据是不包含“ apple”的字符串。
在用户示例中, “ not”关键字用于防止某些属性在“ oneOf”中的一种情况下使用,尽管它们已定义:
{
"properties": {
"connType": { "enum": ["friend", "colleague", "other"] },
"relation": { "not": {} },
"close": { "not": {} }
}
}上例中的“ not”关键字的值是一个空模式。 空模式将验证任何值是否有效,而“ not”关键字将使其无效。 因此,如果对象具有属性relation或close则架构验证将失败。 您可以结合使用“ not”和“ required”关键字来实现相同的目的。
关键字“ not”的另一种用法是定义模式,该模式要求数组包含根据某些模式有效的项目:
{
"not": {
"items": {
"not: {
"type": "integer",
"minimum": 5
}
}
}
}上面的模式要求数据是一个数组,并且包含至少一个大于或等于5的整数项。
V5提案包含关键字“ contains”来满足此要求。
var schema = {
"type": "array",
"contains": {
"type": "integer",
"minimum": 5
}
};
var ajv = Ajv({v5: true}); // enables v5 keywords
var validate = ajv.compile(schema);
validate([3, 4, 5]); // true
validate([1, 2, 3]); // false任务4
您有一个用户数据库,这些数据库都与该用户示例中的模式匹配。 创建一个架构,根据该架构,只有满足所有这些条件的用户才有效:
- 未满21岁或未满60岁的未婚男性
- 具有5个或更少的连接
- 订阅3个或更少的提要
将您的答案放在文件part1/task4/filter_schema.json然后运行node part1/task4/validate进行检查。
测试数据经过简化,因此请不要在架构中使用“ required”关键字。
描述架构的关键字
用户示例中使用的某些关键字不会直接影响验证,但它们描述了架构本身。
“ $ schema”关键字定义该模式的元模式的URI。 模式本身是一个JSON文档,可以使用JSON模式进行验证。 定义任何JSON模式的JSON模式称为元模式。 JSON-schema标准草案4的元模式的URI是http://json-schema.org/draft-04/schema 。
如果扩展标准,建议您使用“ $ schema”属性的其他值。
“ id”是架构URI。 它可以用于使用“ $ ref”关键字从另一个架构引用该架构(或其一部分),请参阅本教程的第二部分。 包括Ajv在内的大多数验证器都允许将任何字符串用作“ id” 。 根据标准,架构ID应该是可用于下载架构的有效URI。
您还可以使用“标题”和“描述”来描述架构。 验证期间不使用它们。 这两个关键字都可以在模式内部的任何级别上使用,以描述模式的某些部分,如在用户示例中所做的那样。
最后任务
创建用户记录的示例,该示例在通过示例用户架构进行验证时将出现8个或更多错误。
将您的答案放在文件part1/task5/invalid_user.json然后运行node part1/task5/validate进行检查。
我们的用户架构仍然有什么大问题?
下一步是什么?
到目前为止,您已经知道该标准定义的所有验证关键字,并且您应该能够创建非常复杂的架构。 随着模式的增长,您将重用其中的某些部分。 可以将模式分为多个部分,甚至多个文件,以避免重复。 我们将在本教程的第二部分中进行此操作。
我们还将:
- 使用架构定义默认值
- 从数据中过滤其他属性
- 使用JSON模式规范版本5提案中包含的关键字
- 定义新的验证关键字
- 比较现有的JSON模式验证器
谢谢阅读!
翻译自: https://code.tutsplus.com/tutorials/validating-data-with-json-schema-part-1--cms-25343