NAME
JSON::Schema::AsType - generates Type::Tiny types out of JSON schemas
VERSION
version 1.0.0
SYNOPSIS
use JSON::Schema::AsType;
my $schema = JSON::Schema::AsType->new( schema => {
properties => {
foo => { type => 'integer' },
bar => { type => 'object' },
},
});
print 'valid' if $schema->check({ foo => 1, bar => { two => 2 } }); # prints 'valid'
print $schema->validate_explain({ foo => 'potato', bar => { two => 2 } });
DESCRIPTION
This module takes in a JSON Schema (http://json-schema.org/) and turns it into a Type::Tiny type.
Strings and Numbers
By default, JSON::Schema::AsType follows the JSON schema specs and distinguish between strings and numbers.
value String? Number?
"a" yes no
1 no yes
"1" yes no
If you want the usual Perl behavior and considers the JSON schema type String to be a superset of Number. That is:
value String? Number?
"a" yes no
1 yes yes
"1" yes yes
Then you can set the object's attribute strict_string to 0. Setting the global variable $JSON::Schema::AsType::strict_string to 0 will work too, but that's deprecated and will eventually go away.
METHODS
new( %args )
my $schema = JSON::Schema::AsType->new(
schema => $json_schema
);
The class constructor. Accepts the following arguments.
- schema => \%schema
-
The JSON schema to compile, as a hashref.
If not given, will be retrieved from
uri.An error will be thrown is neither
schemanoruriis given. - uri => $uri
-
Optional uri associated with the schema. If not provided, a local uri
http://254.0.0.1:$portwill be assigned to the schema. - draft => $version
-
The version of the JSON-Schema specification to use. Accepts
3,4,6,7,2019-09, and2020-12. Defaults to2020-12. - fetch_remote => $boolean
-
If sets to true, allows
fetchto retrieve remote schemas. - registry => $registry
-
JSON::Schema::AsType->new( schema => { '$id' => 'http://localhost/foo', $ref => 'bar', } registry => { 'http://localhost/bar' => { type => 'string' } } );Registry of schemas that can be used by the current schema.
metaschema
Returns the metaschema of the current schema, based on its draft version.
uri
Returns the URI of the schema, as a URI object.
type
Returns the compiled Type::Tiny type.
check( $struct )
Returns true if $struct is valid as per the schema.
validate( $struct )
Returns a short explanation if $struct didn't validate, nothing otherwise.
validate_explain( $struct )
Returns a log explanation if $struct didn't validate, nothing otherwise.
validate_schema
Like validate, but validates the schema itself against its specification.
print $schema->validate_schema;
validate_explain_schema
Like validate_explain, but validates the schema itself against its specification.
draft
Returns the draft version used by the object.
schema
Returns the JSON schema, as a hashref.
fetch( $url )
Fetches the schema at the given $url and returns it as a JSON::Schema::AsType object.
resolve_reference( $ref )
my $sub_schema = $schema->resolve_reference( '#/properties/foo' );
print $sub_schema->check( $struct );
Returns the JSON::Schema::AsType object associated with the type referenced by $ref.
add_vocabulary($vocabulary_role)
$schema->add_vocabulary('Anagram');
Adds a vocabulary to the schema. $vocabulary_role is the name of a role implementing the vocabulary keywords and behaviors. See the section ADDING A VOCABULARY for more details.
ADDING A VOCABULARY
Vocabularies have been introduced in draft 2019-09 of JSON Schema, but they are available in all draft versions in JSON::Schema::AsType. They are, basically, sets of keywords and behaviors that we want our schema to have access to. For JSON::Schema::AsType, they are implemented using roles.
For example, let's say we want to implement a new anagram_of keyword, which would ensure that a string in the schema is an anagram of a provided word. We could create the role Anagram:
package Anagram;
use feature qw/ signatures module_true/;
use Type::Tiny;
use Types::Standard qw/ Str /;
use Moose::Role;
sub _normalize_word($word) {
join '', sort split '', $word;
}
my $anagram_type = Type::Tiny->new(
name => 'Anagram',
constraint_generator => sub($word) {
$word = _normalize_word($word);
return sub {
_normalize_word($_) eq $word;
}
},
deep_explanation => sub($type,$value,@) {
my $p = $type->parameters->[0];
[qq{"$value" is not an anagram of "$p"}];
},
);
sub _keyword_anagram_of($self, $word ) {
# don't check anagrams on non-strings
return ~Str | $anagram_type->of($word)
}
And then, to have a schema use it:
my $schema = JSON::Schema::AsType->new(
schema => {
type => 'string',
anagram_of => 'meat',
}
);
print $schema->check('team'); # 1
print $schema->check('tomato'); # undef
COMPLIANCE TO THE SPECS
JSON::Schema::AsType passes all the JSON schema test suites https://github.com/json-schema-org/JSON-Schema-Test-Suite excepts for the following:
drafts | test file / test
------- | ------------------
all | const.json / float and integers are equal up to 64-bit representation limits
2019-09 | ref.json / refs with relative uris and defs
2019-09 | ref.json / relative refs with absolute uris and defs
2020-12 | pattern.json / pattern with Unicode property escape requires unicode mode
2020-12 | defs.json / *
2020-12 | unevaluatedItems / *
2020-12 | unevaluatedProperties / *
2020-12 | dynamicRef / *
2020-12 | ref / *
Known limitations/design decisions
- JSON Schema assumes a 64-bit representation of floats and integers, whereas JSON::Schema::AsType adheres to whatever the local perl supports.
- For
patterns, JSON::Schema::AsType assumes we always are in unicode mode. - Some hairy
reftests are failing for drafts2019-09and2020-12. For most common uses, that shouldn't be a problem.
SEE ALSO
AUTHOR
Yanick Champoux <yanick@babyl.dyndns.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Yanick Champoux.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.