Skip to main content

Crate corvus_json_schema

Crate corvus_json_schema 

Source
Expand description

A high-performance JSON Schema evaluator (draft 4, 6, 7, 2019-09 and 2020-12), ported from the Corvus.Text.Json V5 runtime evaluator (Corvus.Text.Json.RuntimeEvaluator).

A schema is compiled once into a node graph with pre-digested keyword data, then any number of serde_json::Value instances are evaluated against it: fast (fail-fast, no reporting) with Validator::is_valid, or exhaustively with a JsonSchemaResultsCollector for Basic, Detailed or Verbose results and annotations, with the same rows (paths, messages, order) as the C# collector.

use serde_json::json;

let validator = corvus_json_schema::compile(&json!({
    "type": "object",
    "properties": { "id": { "type": "integer", "minimum": 1 } },
    "required": ["id"]
}))
.unwrap();
assert!(validator.is_valid(&json!({ "id": 3 })));
assert!(!validator.is_valid(&json!({ "id": 0 })));

§Regular expressions and their limits

pattern, patternProperties and the regex format follow ECMA-262. Simple patterns are matched by matchers of the crate’s own and by the regex crate, and everything else (lookarounds, backreferences, modifier groups) by the crate’s own ECMA-262 engine, as each pattern is written.

A schema and an instance may both come from outside, so a pattern is bounded in what it costs. One match against one string may take CompileOptions::pattern_match_limit, one second unless the options say otherwise. A match that reaches it is abandoned and the validation has no answer: Validator::try_validate and the other try_ functions return SchemaEvaluationError::PatternMatchLimit. A pattern longer than 1,048,576 bytes, nested more than 1,000 groups deep or of more than about 16,000 terms does not compile, and SchemaCompilationError::kind is then SchemaCompilationErrorKind::PatternTooLarge, which is not the kind of a pattern that is not valid.

use std::time::Duration;

use corvus_json_schema::{CompileOptions, SchemaCompilationErrorKind, SchemaEvaluationError, compile, compile_with};
use serde_json::json;

// A group read back inside a repetition: on this string the match would run for longer than anyone waits.
let options = CompileOptions { pattern_match_limit: Some(Duration::from_millis(50)), ..CompileOptions::default() };
let validator = compile_with(&json!({ "pattern": r"^(?:(a+)\1*)+$" }), &options).unwrap();
let instance = json!("a".repeat(60) + "b");
match validator.try_validate(&instance) {
    Err(SchemaEvaluationError::PatternMatchLimit(e)) => {
        assert_eq!(e.pattern(), r"^(?:(a+)\1*)+$");
        assert_eq!(e.limit(), Duration::from_millis(50));
    }
    other => panic!("{other:?}"),
}
// is_valid has no way to say so, and answers false.
assert!(!validator.is_valid(&instance));

// A pattern over a limit of size is not a pattern that is not valid.
let error = compile(&json!({ "pattern": "a".repeat(20000) })).unwrap_err();
assert!(matches!(error.kind(), SchemaCompilationErrorKind::PatternTooLarge(large) if large.limit() == "size"));
let error = compile(&json!({ "pattern": "a**" })).unwrap_err();
assert_eq!(error.kind(), &SchemaCompilationErrorKind::InvalidPattern);

Structs§

Annotation
An annotation extracted from verbose results.
CompileOptions
Options for compiling a schema.
JsonDocument
JSON text parsed for evaluation. It borrows the text, for the strings that need no unescaping.
JsonDocumentArray
The items of an array in a JsonDocument.
JsonDocumentObject
The properties of an object in a JsonDocument.
JsonDocumentValue
A value in a JsonDocument: an Instance for crate::Validator::validate_instance.
JsonParseError
The text is not valid JSON, or nests arrays and objects too deeply.
JsonSchemaResultsCollector
Collects the results of an evaluation (JsonSchemaResultsCollector).
PatternMatchLimitError
A validation was abandoned because one match of a pattern or patternProperties regular expression reached its limit. The instance is then neither valid nor not valid.
PatternTooLargeError
A regular expression of a schema is over a limit of size, so the schema was not compiled.
SchemaCompilationError
A schema could not be compiled (an unresolvable reference, an invalid pattern, a pattern over a limit of size). SchemaCompilationError::kind tells the errors of a regular expression apart.
SchemaEvaluationDepthError
The validation was abandoned at a limit, and gave no answer. It is the error of the functions whose error type was there before the limit of a match was (validate, validate_instance, evaluate, evaluate_instance, and inside crate::JsonValidationError::DepthExceeded validate_json and evaluate_json).
SchemaResult
One result row.
Validator
A compiled schema. Cheap to clone and safe to share between threads.

Enums§

Dialect
The JSON Schema dialects the evaluator understands, in specification order.
JsonValidationError
Why JSON text could not be validated, as Validator::validate_json and Validator::evaluate_json report it. Validator::try_validate_json and Validator::try_evaluate_json report a SchemaEvaluationError, which also tells a match of a regular expression that reached its limit from the maximum depth.
Kind
The kind of a JSON value. The discriminants are the evaluator’s type bits, so a type test is one mask operation (and a match that produces a kind compiles to a table, not a jump per value).
ResultsLevel
How much a results collector records.
SchemaCompilationErrorKind
What kind of error a SchemaCompilationError is.
SchemaEvaluationError
Why an evaluation gave no answer. The instance is then neither valid nor not valid.
View
What an instance is.

Constants§

DEFAULT_PATTERN_MATCH_LIMIT
The time one match of a pattern or patternProperties regular expression against one string may take, unless CompileOptions::pattern_match_limit says otherwise.
VERSION
The version of this crate.

Traits§

ArrayView
The items of an array.
Instance
A JSON value the evaluator can read in place. Cheap to copy (a reference or a handle); values reached through it (items, property values, strings) live as long as 'a.
ObjectView
The properties of an object, in their order.

Functions§

collect_annotations
Annotations grouped by instance location, then keyword, then schema location fragment, with parsed values (JsonSchemaAnnotationProducer.WriteAnnotationsTo): { "/name": { "title": { "#/properties/name": "Name" } } }.
compile
Compiles a schema with the default options (2020-12 for documents without $schema, format as an annotation unless the vocabularies assert it).
compile_from_uri
Compiles the schema document at uri, fetched through options.resolve_document (or one of the standard metaschemas).
compile_with
Compiles a schema.
encode_pointer_segment
Encodes a JSON pointer segment (~ as ~0, / as ~1).
enumerate_annotations
The annotations in a verbose collector’s results (JsonSchemaAnnotationProducer.EnumerateAnnotations).
schema_location_fragment
# followed by the schema location, percent-encoded as a URI fragment (upper-case hex, UTF-8).

Type Aliases§

DocumentResolver
Resolves a schema document by absolute URI; returns None if it is unknown.
FormatValidator
A custom format assertion over the string value (or the number’s JSON text, for numbers).