Last active
October 13, 2022 20:54
-
-
Save laat/f91ec60d20544d86738c0e668f102c83 to your computer and use it in GitHub Desktop.
JsonSchema.Net validation in F#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S dotnet fsi --quiet | |
#r "nuget: JsonSchema.Net" | |
// | |
// This file contains a basic example of json schema validation | |
// | |
open Json.Schema | |
open System.Text.Json | |
let schema = | |
JsonSchema.FromText | |
""" | |
{ | |
"$id": "https://example.com/person.schema.json", | |
"$schema": "https://json-schema.org/draft/2020-12/schema", | |
"title": "Person", | |
"type": "object", | |
"properties": { | |
"firstName": { | |
"type": "string", | |
"description": "The person's first name." | |
}, | |
"lastName": { | |
"type": "string", | |
"description": "The person's last name." | |
}, | |
"age": { | |
"description": "Age in years which must be equal to or greater than zero.", | |
"type": "integer", | |
"minimum": 0 | |
} | |
} | |
} | |
""" | |
let document = | |
JsonDocument.Parse | |
""" | |
{ | |
"firstName": "John", | |
"lastName": "Doe", | |
"age": 21 | |
} | |
""" | |
printfn "document is valid: %A" (schema.Validate(document.RootElement).IsValid) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S dotnet fsi --quiet | |
#r "nuget: JsonSchema.Net" | |
// | |
// This file contains an example of validating against a subschema defined in #/$defs/veggies | |
// | |
open Json.Schema | |
open System.Text.Json | |
module JsonSchema = | |
/// get schema from <c>#/$defs/typeName</c> or <c>#/definitions/typeName</c> | |
let tryGetDefinition typeName (schema: JsonSchema) = | |
schema.Keywords | |
|> Seq.choose | |
(function | |
| :? DefsKeyword as res -> Some res.Definitions // JSON Schema Draft 2020-12 $defs | |
| :? DefinitionsKeyword as res -> Some res.Definitions // Old definitions keyword | |
| _ -> None) | |
|> Seq.choose | |
(fun x -> | |
match x.TryGetValue(typeName) with | |
| true, x -> Some x | |
| _ -> None) | |
|> Seq.tryHead | |
let schema = | |
JsonSchema.FromText | |
""" | |
{ | |
"$id": "https://example.com/arrays.schema.json", | |
"$schema": "https://json-schema.org/draft/2020-12/schema", | |
"$defs": { | |
"veggie": { | |
"type": "object", | |
"required": [ "veggieName", "veggieLike" ], | |
"properties": { | |
"veggieName": { | |
"type": "string", | |
"description": "The name of the vegetable." | |
}, | |
"veggieLike": { | |
"type": "boolean", | |
"description": "Do I like this vegetable?" | |
} | |
} | |
} | |
} | |
} | |
""" | |
let document = | |
JsonDocument.Parse | |
""" | |
{ | |
"veggieName": "potato", | |
"veggieLike": true | |
} | |
""" | |
let veggieSchema = | |
schema | |
|> JsonSchema.tryGetDefinition "veggie" | |
|> Option.get | |
printfn "document is valid: %A" (veggieSchema.Validate(document.RootElement).IsValid) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S dotnet fsi --quiet | |
#r "nuget: JsonSchema.Net" | |
// | |
// This file contains an example of validation serialization and an exception | |
// | |
open Json.Schema | |
open System.Text.Json | |
let schema = | |
JsonSchema.FromText | |
""" | |
{ | |
"$id": "https://example.com/person.schema.json", | |
"$schema": "https://json-schema.org/draft/2020-12/schema", | |
"title": "Person", | |
"type": "object", | |
"properties": { | |
"firstName": { | |
"type": "string", | |
"description": "The person's first name." | |
}, | |
"lastName": { | |
"type": "string", | |
"description": "The person's last name." | |
}, | |
"age": { | |
"description": "Age in years which must be equal to or greater than zero.", | |
"type": "integer", | |
"minimum": 0 | |
} | |
} | |
} | |
""" | |
let document = // should not validate | |
JsonDocument.Parse | |
""" | |
{ | |
"firstName": 123 | |
} | |
""" | |
let validationResult = | |
schema.Validate(document.RootElement, ValidationOptions(OutputFormat = OutputFormat.Basic)) | |
// Serialize to a JSON that's readable and well defined | |
// https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.section.10 | |
let validationJson = | |
JsonSerializer.Serialize(validationResult, JsonSerializerOptions(WriteIndented = true)) | |
(* | |
{ | |
"valid": false, | |
"keywordLocation": "#/properties/firstName/type", | |
"instanceLocation": "#/firstName", | |
"error": "Value is number but should be string" | |
} | |
*) | |
// Good for exception messages? | |
if not validationResult.IsValid then | |
failwithf "invalid JSON: %s" validationJson |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment