NAME
JSON::Schema::Corvus - Fast JSON Schema validation (draft 4 to 2020-12) in pure Perl
SYNOPSIS
use JSON::Schema::Corvus;
my $validator = JSON::Schema::Corvus->compile(<<'JSON');
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": { "id": { "type": "integer", "minimum": 1 } },
"required": ["id"]
}
JSON
$validator->is_valid_json('{"id": 3}'); # true
$validator->is_valid_json('{"id": 0}'); # false
$validator->is_valid({ id => 3 }); # Perl data: true
my $collector = JSON::Schema::Corvus::ResultsCollector->new('detailed');
$validator->evaluate_json('{"id": "3"}', $collector);
for my $row (@{ $collector->results }) {
print "$row->{document_evaluation_location}: $row->{message}\n" unless $row->{is_match};
}
DESCRIPTION
A JSON Schema validator for draft 4, 6, 7, 2019-09 and 2020-12, which passes the whole of the JSON-Schema-Test-Suite, with results and annotations. It is pure Perl, with no dependency beyond Perl's core: a port of the Corvus.Text.Json evaluator by way of its Python port. A schema is compiled into Perl, which validates with exactly the checks the schema needs. JSON::Schema::Corvus::XS is the same evaluator on the corvus-json-schema C library, with the same API, and is faster still.
JSON text is parsed by the package's own parser, which keeps numbers exactly as the text says: an integer of any size is an integer, and a number with a fraction or an exponent is a floating point number. A whole number is an integer in every draft, 1.0 included, as it is in the XS package. Parsing is in Perl, so for an instance validated more than once, parse it once into a "Documents" document.
Perl data is accepted too, by the rules JSON::PP follows: a scalar that has a number and has never been used as a string is a number, and any other defined scalar is a string; undef is null; JSON::PP::Boolean objects, Perl's own booleans (5.36 and later), \1 and \0 are booleans; a Math::BigInt is an integer, exactly; a Math::BigFloat is an integer when it is whole and otherwise the nearest floating point number; an object with a TO_JSON method is what that returns. The data is copied before it is validated.
A string of JSON text is read as UTF-8: a string with Perl's UTF8 flag on gives its characters, and one without gives its bytes.
Regular expressions
pattern, patternProperties and format: regex are ECMA-262 regular expressions, run with ECMA-262's meaning (Unicode 17, whatever version of Unicode the Perl has). A pattern is read with the grammar of the u flag, and one that only that grammar refuses with the Annex B grammar of a pattern with no flag. Perl's own engine runs a pattern that is proved to match in time proportional to the text, written out so that none of Perl's own meanings applies; every other pattern (a backreference, a lookbehind, or anything the proof does not prove) runs on the package's own matcher, with the limit of a match (pattern_match_limit). That matcher is in Perl, so a deliberately difficult pattern can reach the limit of one second where the XS package answers: raise the limit, or turn it off, for such patterns from a source you trust.
METHODS
compile
my $validator = JSON::Schema::Corvus->compile($schema, %options);
Compiles a schema, given as JSON text or as Perl data (a reference, or a boolean). The options:
- default_dialect
-
The dialect of a schema without
$schema:draft4,draft6,draft7,draft2019-09ordraft2020-12(the default). - assert_format
-
True asserts
format, false never does; left out (orundef), it follows the vocabularies (the 2020-12 format-assertion vocabulary asserts, everything else annotates). - assert_format_in_legacy_drafts
-
With
assert_formatleft out, assertformatin drafts 4 to 7 too. - assert_content
-
Assert
contentEncodingandcontentMediaTypein draft 7, the only draft that asserts them (default true). - formats
-
Custom format assertions, by name:
{ even => sub { length($_[0]) % 2 == 0 } }. Each is called with the string (for a number, its JSON text) and returns whether it is valid. One takes precedence over the built-in format of its name. - resolve_document
-
sub ($uri)for documents a$refnames: it returns the document as JSON text or as Perl data, orundeffor a document it does not know. The standard metaschemas are built in. - base_uri
-
The base URI of the root document.
- entry_point
-
A reference, relative to the root, to evaluate from, such as
#/$defs/item. - max_depth
-
The depth of in-place recursion on a cycle at which evaluation is abandoned (default 128).
- pattern_match_limit
-
The seconds one match of a
patternorpatternPropertiesregular expression against one string may take (default 1).undefor 0 turns the limit off, for a caller who trusts both the schema and the instances.
An exception a custom format or the resolver throws goes up through the call that ran it.
compile_uri
my $validator = JSON::Schema::Corvus->compile_uri($uri, %options);
Compiles the schema at an absolute URI, fetched through resolve_document (or one of the standard metaschemas).
Validators
- is_valid_json($text)
-
Whether the JSON text is valid.
- is_valid($data)
-
Whether the Perl data is valid.
- is_valid_document($document)
-
Whether a "Documents" document is valid.
- evaluate_json($text, $collector), evaluate($data, $collector), evaluate_document($document, $collector)
-
Evaluates every keyword, replacing the collector's results with this evaluation's, and returns whether the instance is valid.
- source
-
The Perl the schema was compiled into.
A validator may be used any number of times, and in more than one thread.
Documents
my $document = JSON::Schema::Corvus::Document->parse($text);
my $document = JSON::Schema::Corvus::Document->from_data($data);
JSON parsed once, for an instance validated more than once.
Results
my $collector = JSON::Schema::Corvus::ResultsCollector->new($level);
A results collector at the basic level (failures, without messages), detailed (failures, with messages, the default) or verbose (every evaluation, passing and failing, with annotations). Its rows are those of the other Corvus evaluators: the same locations, messages and order. Its methods:
- results
-
The rows of the last evaluation, as an array of hashes with
is_match,message,evaluation_location(the keywords from the root schema),schema_evaluation_location(the schema or keyword within its document) anddocument_evaluation_location(the JSON pointer of the evaluated value). - annotations, annotations_json
-
The annotations of a verbose evaluation, grouped by instance location, keyword and schema location:
{ "/name" => { title => { "#/properties/name" => "Name" } } }, as Perl data or as JSON text. - count, clear
-
The number of rows, and removing them.
Other functions
JSON::Schema::Corvus::encode_json($data) returns the JSON text (UTF-8 bytes) of the JSON value that Perl data is validated as.
ERRORS
Failures are thrown as objects of these classes, which stringify to their message:
- JSON::Schema::Corvus::Error
-
The base class, with
message. Thrown itself for a bad argument or option. - JSON::Schema::Corvus::Error::InvalidJson
-
Text that is not JSON, or not UTF-8.
offsetis the byte offset at which it was found to be invalid. - JSON::Schema::Corvus::Error::Compilation
-
A schema that does not compile: a reference that does not resolve, or a regular expression that is not valid.
- JSON::Schema::Corvus::Error::PatternTooLarge
-
A
Compilationerror for a regular expression over a limit of size: 1,048,576 bytes of pattern, 1,000 levels of groups, or 1,048,576 bytes counted for it as it is read. - JSON::Schema::Corvus::Error::Depth
-
Evaluation recursed in place beyond
max_depth. - JSON::Schema::Corvus::Error::PatternMatchLimit
-
A match of a regular expression reached
pattern_match_limit: the instance is neither valid nor not valid. It has thepatternand thelimit.
Perl data that has no JSON form (a code reference, an object with no TO_JSON, a number that is not finite, or a structure nested more than 512 deep) dies with a message.
SEE ALSO
JSON::Schema::Corvus::XS, https://github.com/corvus-dotnet/Corvus.JsonSchema.
LICENSE
Apache License 2.0. The package holds tables derived from the Unicode Character Database, whose notice is in THIRD-PARTY-NOTICES.txt.