翼度科技»论坛 编程开发 .net 查看内容

Json Schema简介和Json Schema的.net实现库 LateApexEarlySpeed.Json.Schem

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24
什么是Json Schema ?

Json schema是一种声明式语言,它可以用来标识Json的结构,数据类型和数据的具体限制,它提供了描述期望Json结构的标准化方法。
利用Json Schema, 你可以定义Json结构的各种规则,以便确定Json数据在各个子系统中交互传输时保持兼容和一致的格式。
一般来说,系统可以自己实现逻辑来判断当前json是否满足接口要求,比如是否某个字段存在,是否属性值是有效的。但当验证需求变得复杂后,比如有大量嵌套json结构,属性之间的复杂关联限制等等,则容易编写出考虑不全的验证代码。另外,当系统需要动态的json数据要求,比如先由用户自己决定他需要的json结构,然后系统根据用户表达的定制化json结构需求,帮助用户验证后续的json数据。这种系统代码编译时无法确定的json结构,就需要另一种解决方案。
Json Schema就是针对这种问题的比较自然的解决方案。它可以让你或你的用户描述希望的json结构和值的内容限制,有效属性,是否是required, 还有有效值的定义,等等。。利用Json Schema, 人们可以更好的理解Json结构,而且程序也可以根据你的Json Schema验证Json数据。
Json Schema语法的学习见官方介绍
比如下面的一个简单例子,用.net下的Json Schema实现库LateApexEarlySpeed.Json.Schema进行Json数据的验证:
Json Schema (文件:schema.json):
  1. {
  2.   "type": "object",
  3.   "properties": {
  4.     "propBoolean": {
  5.       "type": "boolean"
  6.     },
  7.     "propArray": {
  8.       "type": "array",
  9.       "uniqueItems": true
  10.     }
  11.   }
  12. }
复制代码
Json 数据 (文件:instance.json):
  1. {
  2.   "propBoolean": true,
  3.   "propArray": [ 1, 2, 3, 4, 4 ]
  4. }
复制代码
C# 代码:
  1.             string jsonSchema = File.ReadAllText("schema.json");
  2.             string instance = File.ReadAllText("instance.json");
  3.             var jsonValidator = new JsonValidator(jsonSchema);
  4.             ValidationResult validationResult = jsonValidator.Validate(instance);
  5.             if (validationResult.IsValid)
  6.             {
  7.                 Console.WriteLine("good");
  8.             }
  9.             else
  10.             {
  11.                 Console.WriteLine($"Failed keyword: {validationResult.Keyword}");
  12.                 Console.WriteLine($"ResultCode: {validationResult.ResultCode}");
  13.                 Console.WriteLine($"Error message: {validationResult.ErrorMessage}");
  14.                 Console.WriteLine($"Failed instance location: {validationResult.InstanceLocation}");
  15.                 Console.WriteLine($"Failed relative keyword location: {validationResult.RelativeKeywordLocation}");
  16.             }
复制代码
输出:
  1. Failed keyword: uniqueItems
  2. ResultCode: DuplicatedArrayItems
  3. Error message: There are duplicated array items
  4. Failed instance location: /propArray
  5. Failed relative keyword location: /properties/propArray/uniqueItems
复制代码
LateApexEarlySpeed.Json.Schema中文介绍

项目原始文档:https://github.com/lateapexearlyspeed/Lateapexearlyspeed.JsonSchema.Doc
中文文档:
LateApexEarlySpeed.Json.Schema是2023年12月发布的一个新的.net下的Json Schema实现库,基于截止到2023年12月为止最新版的Json schema - draft 2020.12。
Json Schema验证功能经过了official json schema test-suite for draft 2020.12的测试。(部分排除的用例见下面的已知限制章节)
LateApexEarlySpeed.Json.Schema的主要特点是:

  • 基于微软.net下默认的System.Text.Json而非经典的Newtonsoft.Json
  • 使用简单
  • 和已有的知名且杰出的.net下的一些JsonSchema实现库相比,具有很好的性能 (在common case下,利用BenchmarkDotnet进行的性能测试)。用户请根据自己的使用场景进行性能验证
该实现库之后可能会transfer成开源项目。
基础用法

安装Nuget package
  1. Install-Package LateApexEarlySpeed.Json.Schema
复制代码
  1. string jsonSchema = File.ReadAllText("schema.json");
  2. string instance = File.ReadAllText("instance.json");
  3. var jsonValidator = new JsonValidator(jsonSchema);
  4. ValidationResult validationResult = jsonValidator.Validate(instance);
  5. if (validationResult.IsValid)
  6. {
  7.     Console.WriteLine("good");
  8. }
  9. else
  10. {
  11.     Console.WriteLine($"Failed keyword: {validationResult.Keyword}");
  12.     Console.WriteLine($"ResultCode: {validationResult.ResultCode}");
  13.     Console.WriteLine($"Error message: {validationResult.ErrorMessage}");
  14.     Console.WriteLine($"Failed instance location: {validationResult.InstanceLocation}");
  15.     Console.WriteLine($"Failed relative keyword location: {validationResult.RelativeKeywordLocation}");
  16.     Console.WriteLine($"Failed schema resource base uri: {validationResult.SchemaResourceBaseUri}");
  17. }
复制代码
输出信息

当json数据验证失败后,可以查看错误数据的具体信息:

  • IsValid: As summary indicator for passed validation or failed validation.
  • ResultCode: The specific error type when validation failed.
  • ErrorMessage: the specific wording for human readable message
  • Keyword: current keyword when validation failed
  • InstanceLocation: The location of the JSON value within the instance being validated. The value is a JSON Pointer.
  • RelativeKeywordLocation: The relative location of the validating keyword that follows the validation path. The value is a JSON Pointer, and it includes any by-reference applicators such as "$ref" or "$dynamicRef". Eg:
    1. /properties/width/$ref/minimum
    复制代码
  • SubSchemaRefFullUri: The absolute, dereferenced location of the validating keyword when validation failed. The value is a full URI using the canonical URI of the relevant schema resource with a JSON Pointer fragment, and it doesn't include by-reference applicators such as "$ref" or "$dynamicRef" as non-terminal path components. Eg:
    1. https://example.com/schemas/common#/$defs/count/minimum
    复制代码
  • SchemaResourceBaseUri: The absolute base URI of referenced json schema resource when validation failed. Eg:
    1. https://example.com/schemas/common
    复制代码
性能建议

尽可能的重用已实例化的JsonValidator实例(JsonValidator可以简单理解为代表一个json schema验证文档)来验证json数据,以便获得更高性能
外部json schema依赖的支持

除了自动支持当前schema文档内的引用关系,还支持外部json schema依赖:

  • 本地schema依赖文本
  1. var jsonValidator = new JsonValidator(jsonSchema);
  2. string externalJsonSchema = File.ReadAllText("schema2.json");
  3. jsonValidator.AddExternalDocument(externalJsonSchema);
  4. ValidationResult validationResult = jsonValidator.Validate(instance);
复制代码

  • 远程schema url (实现库将访问网络来获得远程的schema)
  1. var jsonValidator = new JsonValidator(jsonSchema);
  2. await jsonValidator.AddHttpDocumentAsync(new Uri("http://this-is-json-schema-document"));
  3. ValidationResult validationResult = jsonValidator.Validate(instance);
复制代码
自定义keyword的支持

除了json schema specification中的标准keywords之外,还支持用户创建自定义keyword来实现额外的验证需求:
  1. {
  2.   "type": "object",
  3.   "properties": {
  4.     "prop1": {
  5.       "customKeyword": "Expected value"
  6.     }
  7.   }
  8. }
复制代码
  1. ValidationKeywordRegistry.AddKeyword<CustomKeyword>();
复制代码
  1. [Keyword("customKeyword")] // It is your custom keyword name
  2. [JsonConverter(typeof(CustomKeywordJsonConverter))] // Use 'CustomKeywordJsonConverter' to deserialize to 'CustomKeyword' instance out from json schema text
  3. internal class CustomKeyword : KeywordBase
  4. {
  5.     private readonly string _customValue; // Simple example value
  6.     public CustomKeyword(string customValue)
  7.     {
  8.         _customValue = customValue;
  9.     }
  10.     // Do your custom validation work here
  11.     protected override ValidationResult ValidateCore(JsonInstanceElement instance, JsonSchemaOptions options)
  12.     {
  13.         if (instance.ValueKind != JsonValueKind.String)
  14.         {
  15.             return ValidationResult.ValidResult;
  16.         }
  17.         return instance.GetString() == _customValue
  18.             ? ValidationResult.ValidResult
  19.             : ValidationResult.CreateFailedResult(ResultCode.UnexpectedValue, "It is not my expected value.", options.ValidationPathStack, Name, instance.Location);
  20.     }
  21. }
复制代码
  1. internal class CustomKeywordJsonConverter : JsonConverter<CustomKeyword>
  2. {
  3.     // Library will input json value of your custom keyword: "customKeyword" to this method.
  4.     public override CustomKeyword? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
  5.     {
  6.         // Briefly:
  7.         return new CustomKeyword(reader.GetString()!);
  8.     }
  9.     public override void Write(Utf8JsonWriter writer, CustomKeyword value, JsonSerializerOptions options)
  10.     {
  11.         throw new NotImplementedException();
  12.     }
  13. }
复制代码
Format支持

目前实现库支持如下format:

  • uri
  • uri-reference
  • date
  • time
  • date-time
  • email
  • uuid
  • hostname
  • ipv4
  • ipv6
  • json-pointer
  • regex
Format 验证需要显式enable, 当验证数据时,请传入配置好的 JsonSchemaOptions:
  1. jsonValidator.Validate(instance, new JsonSchemaOptions{ValidateFormat = true});
复制代码
如果需要自定义format验证,可以实现一个FormatValidator子类并注册:
  1. [Format("custom_format")] // this is your custom format name in json schema
  2. public class TestCustomFormatValidator : FormatValidator
  3. {
  4.     public override bool Validate(string content)
  5.     {
  6.         // custom format validation logic here...
  7.     }
  8. }
  9. // register it globally
  10. FormatRegistry.AddFormatType<TestCustomFormatValidator>();
复制代码
Other extension usage doc is to be continued .

限制


  • 目前类库关注于验证,暂不支持annotation
  • 因为暂不支持annotation, 所以不支持如下keywords: unevaluatedProperties, unevaluatedItems
  • 目前不支持 content-encoded string
问题报告

欢迎把使用过程中遇到的问题和希望增加的功能发到github repo issue中
More doc is to be written


来源:https://www.cnblogs.com/dotnet-diagnostic/archive/2023/12/26/17927879.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具