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 schema nor uri is given.

uri => $uri

Optional uri associated with the schema. If not provided, a local uri http://254.0.0.1:$port will be assigned to the schema.

draft => $version

The version of the JSON-Schema specification to use. Accepts 3, 4, 6, 7, 2019-09, and 2020-12. Defaults to 2020-12.

fetch_remote => $boolean

If sets to true, allows fetch to 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 ref tests are failing for drafts 2019-09 and 2020-12. For most common uses, that shouldn't be a problem.

SEE ALSO

JSON::Schema
JSV

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.