moonschema JSON Schema · MoonBit

moonschema

moonbitstack/moonschema

One package. A schema is read with Schema::new, and the two questions are valid for a yes or a no and faults for the reasons. Everything else here is a type those answers are made of.

Values

letdraft

pub let draft : Draft

The version assumed when a document does not name one.

2020-12: the current release, and the one OpenAPI 3.1 is defined against. A document that says $schema is read at the version it says, whatever this is set to — the document is more specific than the setting.

letoutput

pub let output : Output

The output format a validation produces unless asked for another.

Flag, because the common case is a guard that wants a yes or a no and collecting errors nobody reads is work nobody asked for. A caller that wants to tell someone what went wrong asks for Basic.

Types

enumDraft

Which version of JSON Schema a document is written against.

The five released versions that are still in use. draft-03 is not here: it predates the $ keywords and nothing has been written against it since 2010. The next release is not here yet either; it arrives as another value of this enum and a keyword table, not as a second validator.

pub(all) enum Draft {
  • Draft4draft-04 (2013). What OpenAPI 3.0 profiles, and what a great deal of Java and Python tooling still emits.
  • Draft6draft-06 (2017). $id replaces id, exclusiveMinimum becomes a number.
  • Draft7draft-07 (2018). The most widely deployed version.
  • Draft20192019-09. Vocabularies, $defs, $recursiveRef, and the annotation-aware unevaluatedProperties.
  • Draft20202020-12. $dynamicRef, prefixItems, and what OpenAPI 3.1 is.
pub fn Draft::of(StringView) -> Self?

The version a $schema URI names.

It answers None for a URI it does not know rather than falling back to a version of its own choosing: a document written against something else is not a document to guess at. Both the http and https spellings are accepted, and a trailing # is optional, because both are found in the wild.

pub fn Draft::uri(Self) -> String

The $schema URI that names this version.

structFault

One reason an instance failed, in the shape the basic output gives it (2020-12 §12.4.2).

pub(all) struct Fault {
  • at : StringWhere in the instance, as a JSON Pointer.
  • schema_at : StringWhere in the schema, as a JSON Pointer.
  • keyword : StringThe keyword that refused it.
  • message : StringWhat that keyword had to say.

enumOutput

How much a validation says when it fails.

The four formats the specification itself defines (2020-12 §12.4), named as it names them.

pub(all) enum Output {
  • FlagWhether it validated, and nothing else. The cheapest, and what a guard on a request wants.
  • BasicA flat list of the errors, each with the location in the instance and in the schema.
  • DetailedThe errors as a tree, with the schema's own structure preserved.
  • VerboseEvery annotation as well as every error, which is what a tool that explains a schema to a person needs.

structSchema

A schema document, read and ready to validate instances against.

The version is the one the document names in $schema, whatever draft said; a document is more specific than a setting. remotes are the documents a $ref may reach outside this one, by the URI each is registered under: this library opens no sockets, so what is not fed to it does not exist.

pub struct Schema
pub fn Schema::faults(Self, Json) -> Array[Fault]

Every reason instance failed, or an empty array when it validated.

This is the basic output (§12.4.2), flattened: each fault says where in the instance it was, which keyword refused it, and where that keyword was.

let schema = @moonschema.Schema::new(
  @json.parse("{ \"type\": \"integer\", \"minimum\": 1 }"),
)
for fault in schema.faults(@json.parse("0")) {
  println(fault.to_string())
}
// the instance: below the minimum (minimum at /minimum)
pub fn Schema::new(Json, draft? : Draft, remotes? : Map[String, Json]) -> Self raise Refused

Read a schema document.

draft is the version to read it at when it does not name one; a $schema it does name wins. remotes are the documents a $ref may reach, each under the URI it is referred to by.

let schema = @moonschema.Schema::new(
  @json.parse("{ \"type\": \"object\", \"required\": [\"id\"] }"),
)
schema.valid(@json.parse("{\"id\": 1}"))   // true
pub fn Schema::valid(Self, Json) -> Bool

Whether instance validates.

This is the flag output (§12.4.1): the cheapest answer, and the one a guard on a request wants. Schema::faults says why not.

let schema = @moonschema.Schema::new(@json.parse("{ \"type\": \"integer\" }"))
schema.valid(@json.parse("7"))          // true
schema.valid(@json.parse("\"seven\""))   // false

Errors

suberrorRefused

Why a schema could not be read.

These are faults in the schema, not in the instance an instance that fails validation produces Faults instead.

pub(all) suberror Refused {
  • Unknown(String)
  • Broken(at~ : String, why~ : String)