走近 JSON Schema

JSON Schema 用于描述 JSON 数据的声明性格式。比如表示一个人的信息 的 JSON:

  {
      "first_name": "George",
      "last_name": "Washington",
      "birthday": "1995-02-22",
      "address": {
          "street_address": "3200 Mount Vernon Memorial Highway",
          "city": "Mount Vernon",
          "state": "Virginia",
          "country": "United States"
      }
  }

那么,描述这个 JSON 的 JSON Schema 就是:

  {
      "type": "object",
      "properties": {
           "first_name": { "type": "string" },
           "last_name": { "type": "string" },
           "birthday": { "type": "string", "format": "date-time" },
           "address": {
           "type": "object",
           "properties": {
               "street_address": { "type": "string" },
               "city": { "type": "string" },
               "state": { "type": "string" },
               "country": { "type" : "string" }
           }
          }
      }
  }

在 JSON 模式中,空对象 或 true 是一个完全有效的模式,它将接受任何有效的 JSON,或者 false 表示不匹配任何内容的模式。

JSON Schema的关键字

type关键字是 JSON Schema 的基础。它指定 Schema 的数据类型。其中,JSON Schema 的基本类型包括 string 、number、object、array、boolean、null。

type关键字可以是一个字符串或数组:

  • 如果是字符串,则是上述基本类型之一的名称。
  • 如果是数组,则必须是字符串数组,其中每个字符串是其中一种基本类型的名称,每个元素都是唯一的。在这种情况下,如果 JSON 片段与_任何_给定类型匹配,则它是有效的。

string 类型

可以使用 minLength 和 maxLength 关键字来限制字符串的长度。对于这两个关键字,该值必须是非负数:

{
  "type": "string", 
  "minLength": 2, 
  "maxLength": 3
}

pattern关键字用于将字符串限制为特定的正则表达式:

{
  "type": "string",
  "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
}

format关键字允许对常用的某些类型的字符串值进行基本语义验证:

/** 
format 的可能取值:
    "date-time":日期和时间在一起,例如, 2018-11-13T20:20:39+00:00。
    "time":draft7的时间,例如,20:20:39+00:00
    "date":draft7的日期,例如,2018-11-13。
    "hostname": Internet 主机名
    "idn-hostname":国际化 Internet 主机名
    "ipv4":IPv4 地址
    "ipv6":IPv6 地址
    "uri":通用资源标识符 (URI) 。
    "uri-reference":一个 URI 引用(URI 或相对引用)
    "iri":“uri”的国际化等价物。
    "iri-reference":“uri-reference”的国际化等价物
    "uri-template":一个 URI 模板(任何级别)
    "json-pointer":一个 JSON 指针
    "relative-json-pointer":一个相对 JSON 指针。
    "regex":正则表达式。
*/

{ 
  "type": "string", 
  "format": "date-time" 
}

number 类型

integer类型用于整数。JSON 没有针对整数和浮点值的不同类型。因此,有无小数点并不足以区分整数和非整数:

{ "type": "integer" }

1.0 // ok
1   // ok

multipleOf关键字将数字限制为给定数字的倍数 。它可以设置为任何正数:

{
    "type": "number",
    "multipleOf" : 10
}

minimummaximum关键字的组合指定的 数字的范围(或exclusiveMinimum和 exclusiveMaximum用于表示排他范围):

{
  "type": "number",
  "minimum": 0,
  "exclusiveMaximum": 100
}

object 类型

对象是 JSON 中的映射类型。他们将“键”映射到“值”。在 JSON 中,“键”必须始终是字符串。

properties关键字定义对象的属性(键值对)的 。properties的值是一个对象,其中每个键是属性的名称,每个值是用于验证该属性的模式。此properties关键字将忽略与关键字中的任何属性名称不匹配的任何属性。

additionalProperties关键字用于控制的额外的东西。默认情况下,允许任何其他属性。将additionalProperties架构设置 为false意味着不允许其他属性:

{
  "type": "object",
  "properties": {
    "number": { "type": "number" },
    "street_name": { "type": "string" },
    "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
  },
  "additionalProperties": false
}

也可以给 additionalProperties 使用非布尔模式对实例的其他属性设置更复杂的约束:

{
  "type": "object",
  "properties": {
    "number": { "type": "number" },
    "street_name": { "type": "string" },
    "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
  },
  "additionalProperties": { "type": "string" }
}

patternProperties将正则表达式映射到模式。如果属性名称与给定的正则表达式匹配,则属性值必须针对相应的架构进行验证:

{
  "type": "object",
  "patternProperties": {
    "^S_": { "type": "string" },
    "^I_": { "type": "integer" }
  }
}

required关键字提供必选的属性列表,采用零个或多个字符串的数组。这些字符串中的每一个都必须是唯一的:

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "email": { "type": "string" },
    "address": { "type": "string" },
    "telephone": { "type": "string" }
  },
  "required": ["name", "email"]
}

minPropertiesmaxProperties关键字来限制对象上的属性数量 。这些中的每一个都必须是非负整数:

{
  "type": "object",
  "minProperties": 2,
  "maxProperties": 3
}

array 类型

不加限制的数组类型的模式,元素可以是不同类型:

{ "type": "array" }

[1, 2, 3, 4, 5] // OK
[3, "different", { "types" : "of values" }] // OK

items关键字设置为单个模式,将用于验证数组中所有元素:

{
  "type": "array",
  "items": {
    "type": "number"
  }
}

items是单模式时,additionalItems关键字没有意义,不应使用。

items关键字设置为一个数组,逐个指定,其中每个项目都是一个模式,对应于JSON 数组的每个索引:

{
  "type": "array",
  "items": [
    { "type": "number" },
    { "type": "string" },
    { "enum": ["Street", "Avenue", "Boulevard"] },
    { "enum": ["NW", "NE", "SW", "SE"] }
  ]
}

additionalItems关键字控制如果有超过元组内 items 属性定义的附加元素,元组是否有效。additionalItems如果设置为false,则数组中元素只可以不大于模式个数。同样可以使用非布尔模式来限制附加项可以具有的值来表达更复杂的约束。

minItems和 maxItems关键字指定数组的长度。每个关键字的值必须是非负数:

{
  "type": "array",
  "minItems": 2,
  "maxItems": 3
}

contains关键字指定模式只需要针对数组中的存在进行验证:

{
   "type": "array",
   "contains": {
     "type": "number"
   }
}

["life", "universe", "everything", 42] // OK,包含一个number元素
["life", "universe", "everything", "forty-two"]  // not OK,不包含number元素
[1, 2, 3, 4, 5] // OK

uniqueItems关键字设置为true,可以限制数组中的每个元素都是唯一的:

{
  "type": "array",
  "uniqueItems": true
}

[1, 2, 3, 4, 5] // OK
[1, 2, 3, 3, 4]  // not OK
[] // OK空数组总是通过

boolean 类型和null 类型

boolean 只匹配(===)两个特殊值:true和 false。null 只匹配(===)一个值:null。

enum 枚举

enum关键字用于将值限制为一组固定的值。它必须是一个包含至少一个元素的数组,其中每个元素都是唯一的:

{
  "enum": ["red", "amber", "green", null, 42]
}

"red" // OK
null // OK
42 // OK
0  // not OK

常量 

 const关键字被用于限制值为一个常量值。

通用关键字

readOnlywriteOnly通常用于 API 上下文中。readOnly表示该值可读不可改,可用于说明一个更改值的PUT请求将得到一个400 Bad Request的响应。writeOnly表示该值可已修改但是不可以读,可用于说明可通过PUT请求来设置值,但通过GET请求来检索该记录时不能获取该值 。

default关键字指定一个默认值。该值不用于在验证过程中填充缺失值。

titledescription关键字必须是字符串。title最好是简短的,而description提供模式描述的数据因此会有更长的说明。

合并类型

anyOf关键字模式指定数据至少满足一个给定子模式。

oneOf关键字模式指定数据必须只满足一个给定子模式。

not关键字模式指定数据不能满足任意给定子模式。

条件类型

ifthenelse关键字允许基于另一种模式的结果来应用子模式,当符合if子schema条件,则对then的子schema条件进行校验,若if子schema条件不通过,则走else子schema条件校验:

{
  "type": "object",
  "properties": {
    "street_address": {
      "type": "string"
    },
    "country": {
      "default": "United States of America",
      "enum": ["United States of America", "Canada"]
    }
  },
  "if": {
    "properties": { "country": { "const": "United States of America" } }
  },
  "then": {
    "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
  },
  "else": {
    "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
  }
}

结合 allof 关键字,可以 达到 if... else if ... else .... 的效果:

{
  "type": "object",
  "properties": {
    "street_address": {
      "type": "string"
    },
    "country": {
      "default": "United States of America",
      "enum": ["United States of America", "Canada", "Netherlands"]
    }
  },
  "allOf": [
    {
      "if": {
        "properties": { "country": { "const": "United States of America" } }
      },
      "then": {
        "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
      }
    },
    {
      "if": {
        "properties": { "country": { "const": "Canada" } },
        "required": ["country"]
      },
      "then": {
        "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
      }
    },
    {
      "if": {
        "properties": { "country": { "const": "Netherlands" } },
        "required": ["country"]
      },
      "then": {
        "properties": { "postal_code": { "pattern": "[0-9]{4} [A-Z]{2}" } }
      }
    }
  ]
}

递归

$ref关键字引用自己的子schema片段,实现递归模式,可以用于树形结构的描述 :

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "children": {
      "type": "array",
      /** #代表最外层 */
      "items": { "$ref": "#" }
    }
  }
}

/**

{
  "name": "Elizabeth",
  "children": [
    {
      "name": "Charles",
      "children": [
        {
          "name": "William",
          "children": [
            { "name": "George" },
            { "name": "Charlotte" }
          ]
        },
        {
          "name": "Harry"
        }
      ]
    }
  ]
}

*/

但是请注意,$ref对另一个的引用$ref可能会导致解析器中的无限循环,并且是明确禁止的 

JSON Schema 的使用场景

1. 数据验证

利用 jsonschema 库对数据做验证:

import { Validator } from 'jsonschema';
const v = new Validator();
const instance = 4;
const schema = {"type": "number"};
console.log(v.validate(instance, schema));

在实际开发中,通过预先写好的脚本对返回接口进行批量的数据校验。

2. 根据 JSON Schema 生成数据采集 UI

由于每一种 schema 类型其实可以对应了一种 UI 展示,那么一条 Schema 其实是可以生成一个表单。在表单的 UI 逻辑中保证在提交表单前,数据是符合 Schema 规则的,表单验证通过后,得到的就是符合 Schema 的 JSON 数据。也就是说,基于符合 Schema 规则的配置,逻辑上就能自动渲染出功能完整的表单UI。

3. 生成JSON格式可读文档

可以基于现有的 JSON 来生成 JSON Schema,快速生成 JSON 格式规范,相当于一份可读文档,减少了团队之间的沟通理解成本。JSON Schema Tool

4. 提供更为准确可靠的mock数据

基于JSON Schema提供多种校验约束条件,可以使用它原生的能力来生成更为准确可靠的mock数据。Fake your JSON-Schemas!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫96

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值