問題 對於驗證複雜JSON數據是否合法的需求,通常的解決方式是標準JSON Schema,.Net下有對應的JSON Schema實現庫。應用程式通常需要將標準JSON schema傳入實現庫,來做後續的數據驗證。這裡有一種情況,就是如果使用者不太瞭解標準JSON Schema格式,但又希望能在自己 ...
問題
對於驗證複雜JSON數據是否合法的需求,通常的解決方式是標準JSON Schema,.Net下有對應的JSON Schema實現庫。應用程式通常需要將標準JSON schema傳入實現庫,來做後續的數據驗證。這裡有一種情況,就是如果使用者不太瞭解標準JSON Schema格式,但又希望能在自己的service中使用其強大的功能,或者適配需要JSON Schema的其他service。
解決方案
如果不熟悉標準JSON Schema,可以用Lateapexearlyspeed.Json.Schema 實現庫的 fluent schema builder模式 來創建 JSON Schema 驗證器。
這種fluent schema builder用法的介面設計思路是不完全與標準json schema的格式和命名保持一致。標準JSON Schema雖然強大,但大多開發者一般更熟悉“強類型”風格,因此實現庫的fluent schema builder在配置時會先“問”用戶他們期望哪種JSON token類型,然後在後續鏈式調用時會基於當前限定的JSON token類型繼續“追問”相關的驗證需求。通過這種調用方式,開發者會寫出更安全的驗證代碼,利用IDE也會有更友好的使用體驗。如下:
var b = new JsonSchemaBuilder();
b.ObjectHasProperty("A", b => b.IsJsonString().HasMinLength(5))
.HasProperty("B", b => b.IsJsonNumber().IsGreaterThan(1).IsLessThan(10))
.HasProperty("C", b => b.IsJsonArray().HasMinLength(5).HasItems(b =>
{
b.NotJsonNull();
}))
.HasProperty("D", b => b.Or(
b => b.IsJsonFalse(),
b => b.IsJsonNumber().Equal(0),
b => b.IsJsonObject().HasCustomValidation((JsonElement element) => element.GetProperty("Prop").ValueKind == JsonValueKind.True,
jsonElement => $"Cannot pass my custom validation, data is {jsonElement}")
)
);
JsonValidator jsonValidator = b.BuildValidator();
jsonValidator.Validate(...);
看起來風格是不是很熟悉,即使沒接觸過JSON Schema,相信也能理解上面的.Net代碼。
目前 fluent schema builder 模式下支持的驗證方法:
- NotJsonNull
- IsJsonTrue
- IsJsonFalse
- IsJsonBoolean
- IsJsonNull
- IsJsonString:
- Equal
- IsIn
- HasMaxLength
- HasMinLength
- HasPattern
- HasCustomValidation
- NotMatch
- EndsWith
- StringEqual
- StringHasPattern
- IsJsonNumber:
- Equal
- IsIn
- IsGreaterThan
- IsLessThan
- NotGreaterThan
- NotLessThan
- MultipleOf
- HasCustomValidation
- IsJsonArray:
- SerializationEquivalent
- HasItems
- HasLength
- HasMaxLength
- HasMinLength
- HasUniqueItems
- HasCustomValidation
- Contains
- NotContains
- Equivalent
- HasCollection
- Empty
- NotEmpty
- Single
- ArrayHasItems
- ArrayContains
- IsJsonObject:
- SerializationEquivalent
- HasProperty
- HasCustomValidation
- Equivalent
- HasNoProperty
- ObjectHasProperty
- Or
其中還有HasCustomValidation() overloads 重載方法可以為 JSON樹中的指定節點 創建更高級的自定義驗證需求。
不僅想驗證JSON數據,還想用 代碼Build出來的 Json驗證器 來生成 JSON Schema ?
也可以的
string standardJsonSchema = jsonValidator.GetStandardJsonSchemaText();
註意:
為了支持更高級和友好的驗證體驗,雖然 Lateapexearlyspeed.Json.Schema 實現庫在其內部實現時儘可能使用標準JSON Schema keywords, 但一些Build方法會用到“擴展”keywords,因此當你用了那些Build()生成了 JsonValidator
實例後, 將不支持調用 GetStandardJsonSchemaText()
,因為擴展keywords無法放回標準JSON Schema且被其他application 所認識,如下:
var builder = new JsonSchemaBuilder();
builder.IsJsonNumber().HasCustomValidation((double _) => true, _ => "");
JsonValidator jsonValidator = builder.BuildValidator();
Assert.Throws<NotSupportedException>(() => jsonValidator.GetStandardJsonSchemaText());
牽扯到擴展keywords的Build方法有:
- HasCustomValidation(...)
- HasNoProperty()
- NotContains()
- StartsWith()
- EndsWith()
總結
對於驗證JSON數據方面的複雜需求,可以用JSON Schema解決。
對於不希望直接交互JSON Schema格式的service來說,可以用.Net下的 Lateapexearlyspeed.Json.Schema 實現庫的 fluent schema builder模式,通過寫代碼的形式生成JSON驗證器。
對於希望用強類型風格的代碼生成JSON Schema的需求,也可以用 Lateapexearlyspeed.Json.Schema 實現庫的 fluent schema builder模式。
Github repo: https://github.com/lateapexearlyspeed/Lateapexearlyspeed.JsonSchema, 歡迎將使用時發現的問題提到issue。