Json Schema

发表信息: by

什么是Json Schema

json schema 本身便是json字符串,它用来描述和校验另外的一个json是否正确。 json schema 中提供了可穷举的校验规则(当然,这是基于json的格式是可预见,可穷举的)

举个简单的例子来真实感受下 jsonschema 和 json 之间的关系:

json

{
    "personName": "gc",
    "personAge":23,
    "personTag":"Optimistic",
    "personLatitude": 123.01,
    "personLongitude": 125.12
}

json schema

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type":"object",
    "properties":{
        "personName":{
            "type":"string",
            "maxLength":20,
            "minLength":2
        },
        "personAge":{
            "type":"integer",
            "minimum": 20,
            "maximum": 25
        },
        "personTag":{
            "type":"string",
            "enum":["Optimistic","Earnest","Hello","World"]
        },
        "personLatitude":{
            "type":"number"
        },
        "personLongitude":{
            "type":"number"
        }
    }
}

这里提供一个用json schema 校验 json 的前端界面: json shema validation

Json Schema 校验关键字

通用关键字

title

title 必须是一个string,并无实际用途,只是做标注

description

description 必须是一个string, 无实际用途,标注

default

default 默认值,当不存在该属性的时候,则默认填充的值

type

type 必须是 ["integer", "string", "number", "object", "array", "boolean", "null"] 六种类型之一,number 和 integer 的区别在于 number 可以匹配任何数值(可以理解为java中的Double类型),而 integer 只可以匹配整数类型(可以理解为java中的Integer)

enum

enum 表示枚举类型,即json中的值必须是enum穷举中的任何一个,往往配合 type 为 ["integer", "number", "string"] 这三个使用,使用方式如下:

// schema
{
    "type":"object",
    "properties":{
        "myEnum":{
            "type":"string",
            "enum":["ENUM1", "ENUM2", "ENUM3"]
        }
    }
}

// json
{
    "myEnum":"ENUM1" //success
    // "myEnum": "ENUM4"  faile
}
    

Number 类型

Number 与 Integer 的关键字一样

multipleOf

nultipleOf 必须是一个Number值(举例为值为a),则json中该字段的值必须是a的倍数

maximum

maximum 必须是一个Number值(举例值为a),则json中的该字段的值必须 <= a

minimum

minimum 必须是一个Number值(举例值为a),则json中的该字段的值必须 >= a

exclusiveMaximum

exclusiveMaximum 必须是一个boolen值,如果为true,表示 json中的值必须 < maximum

exclusiveMinimum

exclusiveMinimum 必须是一个boolean值,如果为true,表示 json中的值必须 > minimum

demo


// json schema
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "personAge": {
            "type":"integer",
            "maximum": 20,
            "minumum": 2,
            "exclusiveMinimum":true,
            "exclusiveMaxinum":false
        }
    }
}
    

// json value
{
    "personAge": 18 //success  value scope = (2, 20]
}

String 类型

maxLength

maxLength 必须是一个正整数(举例值为a),则json中的该字段的字符串长度必须 <= a

minLength

minLength 必须是一个正整数(举例值为a),则json中的该字段的字符串长度必须 >= a

pattern

pattern 必须是一个字符串,且是一个有效的正则表达式,该表达式必须满足 [ECMA 262] 定义

demo


// json schema
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "personName": {
            "type":"string",
            "maxLength": 20,
            "minLength": 2,
            "pattern": "^g[a-z]*c$"
        }
    }
}

// json value
{
    "personName":"gc" //success
    // failures  ->    "personName":"g"; "personName":"gx"; "personName":"ggggggggggggggggggccc"
}

Arrays 类型

items

items 表示array中元素的具体类型,json值必须所有的都满足这个类型,才会表示验证成功。

additionalItems

additionalItems 是否支持添加其他数组项, 校验数组项的时候可以分为两种校验方式

  • 对数组中的每一项按照相同的规则校验
  • 对数组中的不同项按照不同规则校验

而 additionalItems 就是为了标明这一点,具体见demo

maxItems

maxItems 最大items长度,必须是正整数 <=

minItems

minItems 最小items长度,必须是正整数 <=

uniqueItems

uniqueItems 是否唯一值,必须是boolean, 如果true,则items内部不允许重复

contains

contains

demo

  • List validation: 对数组中的每一项按照同一个规则校验
// json schema
{
    "type":"object",
    "properties":{
        "myList":{
            "items":{
                "type":"string",
                "maxLength":10
            },
            "maxItems":3,
            "uniqueItems": true
        }
    }
}

// json value
{
    "myList":["hello", "world", "gc"]
}
  • Tuple validation: 针对元素在数组中的位置来校验不同规则
// json schema
{
    "type":"object",
    "properties": {
        "myList": {
            "items":[
                {
                    "type":"string"
                },
                {
                    "type":"integer"
                },
                {
                    "type":"boolean"
                }
            ],
            "additionalItems": false
        }
    }
}

// json value
{
    "myList":["gc", 1, true] // success;  ["gc", 1] success; ["gc", 1, true, "gc"] faile
}

从上面的比较可以看出相关的差别,注意 additionalItems=false的时候,只能校验真实值比规则少的情况,如果真实值比规则多,则失败(json value 给出了三种情况 = < > )

Object 类型

maxProperties

maxProperties 必须是一个正整数(举例a),则json中该字段的属性必须 <= a 个

minProperties

minProperties 必须是一个正整数(举例a),则json中该字段的属性必须 >= a 个

required

required 必须是一个list, 表示该object类型的哪些字段是必须的存在且不为null的

properties

properties 必须是一个object类型,表示着对该object字段的每个属性的jsonchema

dependencies

dependencies 必须是一个object类型,表示哪些属性的存在必须依赖另外一些属性的存在

patternProperties

patternProperties 必须是一个object,会判断所有属性名匹配上的都必须满足一定的条件

additionalProperties

additionalProperties 必须是一个object, 表示json可以出现object未定义,但是满足一定条件的数据

demo

// json schema
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties":{
        "itemName":{
            "type":"string",
            "maxLength": 10
        },
        "itemPrice":{
            "type":"number"
        }
    },
    "required": ["itemPrice"],
    "dependencies": {
        "itemPrice": ["itemName"] // 表示itemPrice存在必须在itemName存在的前提下
    }
}

// json value
{
    "itemName":"1234567890",
    "itemPrice":10
}

规则

使用

这里提供了kotlin语言的使用姿势,如果想要知道其他语言的使用姿势,请参考官方文档

gradle引入相关依赖包

compile("com.github.java-json-tools:json-schema-validator:2.2.8")

schema.json

{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-06/schema#",
  "type": "object",
  "properties": {
    "item": {
      "type": "object",
      "properties": {
        "itemName": {
          "type": "string",
          "format": "date-time"
        },
        "itemPrice": {
          "type": "number",
          "default": 0
        },
        "itemCount": {
          "type": "integer",
          "default": 0,
          "minimum": 10
        },
        "itemTags": {
          "type": "string",
          "enum": [
            "hello",
            "world"
          ]
        },
        "skus": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "skuName": {
                "type": "string",
                "default": ""
              },
              "skuPrice": {
                "type": "number",
                "default": 0,
                "maximum":20
              }
            }
          }
        }
      }
    }
  }
}

value.json

{
  "item": {
    "itemName": "2017-11-12T22:30:20Z",
    "itemPrice": 5.6,
    "itemCount": 11234567890123456789,
    "itemTags": "hello",
    "skus": [
      {
        "skuName": "gc_sku1",
        "skuPrice": 10.2
      },
      {
        "skuName": "gc_sku2",
        "skuPrice": 21
      }
    ]
  }
}

kotlin代码

package json.schame

import com.fasterxml.jackson.databind.JsonNode
import com.github.fge.jackson.JsonLoader
import com.github.fge.jsonschema.examples.Utils
import com.github.fge.jsonschema.main.JsonSchemaFactory
import entity.ItemDTO

fun main(args: Array<String>) {
    val schemaUrl = ItemDTO::class.java.classLoader.getResource("schema.json")
    val valueUrl = ItemDTO::class.java.classLoader.getResource("value.json")

    val jsonSchemaNone = JsonLoader.fromURL(schemaUrl)
    val jsonValueNone = JsonLoader.fromURL(valueUrl)

    val factory = JsonSchemaFactory.byDefault();
    val jsonSchema = factory.getJsonSchema(jsonSchemaNone);

    println(jsonSchema.validate(jsonValueNone, true))
}

源码的git地址下面已经给出,更详细的使用请参考源码

参考

上面所描述的既可以满足基本的json校验,当然也会有更加花哨的玩法,更详细文档下面给出链接