json schema实际运用

Posted 上官云霆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了json schema实际运用相关的知识,希望对你有一定的参考价值。

一、背景

根据实际需求,发现前后端都需要对数据进行校验,且校验字段较多。为避免在代码中加入繁琐的判断,且能前后端保持统一标准,我们使用JSON schema规范来进行数据的校验。

二、JSON Schema

2.1 定义

json-schema 中文意思是 JSON的模式。定义一个JSON的规范,对数据的格式进行约束。比如数据的类型,数字number,字符串 string, 对象Object;数字的大小和区间范围;是否要求必填等等;

2.2 例子

2.2.1 要求

如下是一个校验字段fieldA,fieldB,fieldC的样例。我们要求fieldA是字符串,且值为testString;fieldB是数字类型,大于0(不等于0);三个字段为必填字段。


  "type": "object",
  "properties": 
    "fieldA": 
      "type": "string",
      "enum": [
        "testString"
      ]
    ,
    "fieldB": 
      "type": "number",
      "exclusiveMinimum": 0
    
  ,
  "required": [
    "fieldA",
    "fieldB",
    "fieldC"
  ]

2.2.2 待验证数据


  "fieldA": "test",
  "fieldB": 0

2.2.3 验证

在线验证地址 https://jsonschemalint.com/#!/version/draft-07/markup/json

2.3 版本

json schema 存在多个版本,当前最新版本为draft-07。 不同版本之间规范也不同。部分实现json schema框架默认draft4,可能大家使用过程中会造成麻烦。为了统一规范,可以在后续实现中,显式设置版本号。当然也可是每条检验规范显示设置一个版本号,不过那样太麻烦了。

版本exclusiveMaximumexclusiveMaximum
draft-04取值为 true false,与minimum结合使用,举例 a>0,则exclusiveMaximum: true, minimum:0取值为 true false,与maximum结合使用,举例 a<0,则exclusiveMaximum: true, maximum:0
draft-07数字,举例 a>0,则exclusiveMinimum : 0数字,举例 a<0,则exclusiveMaximum: 0

三、实现

第二部分只是定义了一个规范,现在讲述一下如何实现。虽然JSON schema是脱离语言的,但是实现还是跟语言相关的。

3.1 前端

框架地址介绍是否选用
ajvhttps://github.com/ajv-validator/ajvdraft-07, -06, -04 for Node.js and browsers - supports custom keywords and $data reference (MIT)选用
djvhttps://github.com/korzio/djvdraft-06, -04 for Node.js and browsers (MIT)
Hyperjump JSVhttps://github.com/jdesrosiers/json-schema2019-09, draft-07, -06, -04 Built for Node.js and browsers. Includes support for custom vocabularies. (MIT)
vue-vuelidate-jsonschemahttps://github.com/mokkabonna/vue-vuelidate-jsonschemadraft-06 (MIT)
@cfworker/json-schema@cfworker/json-schema2019-09, draft-07, -06, -04 Built for Cloudflare workers, browsers, and Node.js (MIT)

选用ajv。ajv 是最优的选择。
ajv 是对 JSON Schema 支持最全的一个库;
性能在现有的库中也很优越, 排在第二位,;
排第一位 djv 没有实现 JSON Schema 的最新特性, 我们需要使用最新版规范draft-07;
ajv 与 djv 性能上很接近, 且 ajv比djv的性能更优越;
ajv的社区比djv活跃;

3.1.1 引入

npm install ajv

3.1.2 demo代码

// or ESM/TypeScript import
import Ajv from "ajv"
// Node.js require:
const Ajv = require("ajv")

const ajv = new Ajv() // options can be passed, e.g. allErrors: true
// 规范
const schema = 
  type: "object",
  properties: 
   r93#: type:"string", enum:["a"],
   r94#: type:"string", enum:["b"],
    r156#:anyOf:[type:"number",exclusiveMinimum:0,type:"number",exclusiveMaximum:0],
  ,
  required: ["r93#","r94#",,"r156#"],
  additionalProperties: false,

// 待校验的数据
const data = 
  r156#: 0,
   r93#: "1",
   r94#: "b",


const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)

3.2 后端

框架地址介绍是否选用
networknt/json-schema-validatorhttps://github.com/networknt/json-schema-validatordraft-07, -06, -04 Support OpenAPI 3.0 with Jackson parser (Apache License 2.0)选用
everit-org/json-schemaeverit-org/json-schemadraft-07, -06, -04 (Apache License 2.0)
snowy-jsonhttps://github.com/ssilverman/snowy-json2019-09, draft-07, -06 Uses Maven for the project and Gson under the hood. (GNU Affero General Public License v3.0)

后端选用networknt框架。根据框架比较,

1.networknt是耗时最少的;

2.支持jackson;

3.最小侵入,只引入一个jar包,不会造成冲突;

3.支持高版本jdk,jdk1.8以上,;

4.社区比较活跃。

3.2.1 引入

<dependency>
    <groupId>com.networknt</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>1.0.72</version>
</dependency>

3.2.2 demo代码

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SpecVersion;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;

public class JsonSchemaUtil 

    public static boolean getPatternIdByRule(String checkExpression, JsonNode json) 
        if (StringUtils.isBlank(checkExpression)) 
            return false;
        
        try 
            ObjectMapper mapper = new ObjectMapper();
            JsonNode rootNode = mapper.readTree(checkExpression);
            // 需要明确指定版本为draft7
            JsonSchemaFactory validatorFactory = JsonSchemaFactory
                    .builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7))
                    .objectMapper(mapper)
                    .build();
            JsonSchema newSchema = validatorFactory.getSchema(rootNode);
            if (CollectionUtils.isNotEmpty(newSchema.validate(json))) 
                return false;
             else 
                return true;
            
         catch (Exception e) 
            e.printStackTrace();
        

        return false;
    

    public static void main(String[] args) 
        ObjectMapper newMapper = new ObjectMapper();
        Map<String, Object> ruleMap = new HashMap<>();
        ruleMap.put("r156#", 0);
        ruleMap.put("r93#", "1");
        ruleMap.put("r94#", "b");
        JsonNode json = newMapper.valueToTree(ruleMap);
        System.out.println("空对象 校验成功 " + getPatternIdByRule("", json));
        System.out.println("r156#  校验失败 " + getPatternIdByRule(" \\"type\\":\\"object\\", \\"properties\\": \\"r156#\\":\\"anyOf\\":[\\"type\\":\\"number\\",\\"exclusiveMinimum\\":0,\\"type\\":\\"number\\",\\"exclusiveMaximum\\":0], \\"required\\":[\\"r156#\\"] ", json));
        System.out.println("r93#   校验失败 " + getPatternIdByRule(" \\"type\\":\\"object\\", \\"properties\\": \\"r93#\\": \\"type\\":\\"string\\", \\"enum\\":[\\"a\\"]  ,\\"required\\": [\\"r93#\\"]  "
                , json));
        System.out.println("r94#   校验成功 " + getPatternIdByRule(" \\"type\\":\\"object\\", \\"properties\\": \\"r94#\\": \\"type\\":\\"string\\", \\"enum\\":[\\"b\\"]  ,\\"required\\": [\\"r94#\\"]  "
                , json));

    


#四、坑

有些坑是要避开的

  1. 要显示设置json schema的版本?

不同版本的json schema规范是不一样的,可详见 2.3 版本的 介绍,当前最新版本是draft07。举例,后端networknt框架 可调用builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7))指定

  1. ajv 和 networknt 是目前最好的选择吗?

通过比较,ajv 和 networknt 是目前最好的选择。当然大家可以根据实际情况选择

3.不同框架使用的JSONjar一样吗?

不一样。比如 后端networknt框架使用jackson, 后端everit框架使用org.json

参考资料

json schema介绍 https://blog.csdn.net/liuxiao723846/article/details/108523139

json schema介绍 https://cloud.tencent.com/developer/article/1617902

json schema介绍 https://www.shouxicto.com/article/2783.html

在线编辑和校验 https://jsonschemalint.com/#!/version/draft-07/markup/json

以上是关于json schema实际运用的主要内容,如果未能解决你的问题,请参考以下文章

json schema实际运用

JSON解析器之json schema校验及代码实现

JSON schema与表单验证

第998期JSON schema与表单验证

接口测试框架实战| 搞定 Schema 断言

JSON Schema