Skip to content

Instantly share code, notes, and snippets.

@laat
Last active October 13, 2022 20:54
Show Gist options
  • Save laat/f91ec60d20544d86738c0e668f102c83 to your computer and use it in GitHub Desktop.
Save laat/f91ec60d20544d86738c0e668f102c83 to your computer and use it in GitHub Desktop.
JsonSchema.Net validation in F#
#!/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)
#!/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)
#!/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