View Source JSV.Vocabulary behaviour (jsv v0.3.0)
Behaviour for vocabulary implementation.
A vocabulary module is used twice during the lifetime of a JSON schema:
- When building a schema, the vocabulary module is given key/value pairs such
as
{"type", "integer"}
or{"properties", map_of_schemas}
and must consume or ignore the given keyword, storing custom validation data in an accumulator for further use. - When validating a schema, the module is called with the data to validate and the accumulated validation data to produce a validation result.
Summary
Types
Represents the accumulator initially returned by init_validators/1
and
accepted and returned by handle_keyword/4
.
Represents the final form of the collected keywords after the ultimate
transformation returned by finalize_validators/1
.
Callbacks
Returns the priority for applyting this module to the data.
Functions
By using this module you will
Defines a handle_keyword/4
callback that will return the current
accumulator without changes, but preventing other vocabulary modules with
lower priority (higher number) to be called with this keyword.
Defines a handle_keyword/4
callback that will return :ignore
for any
given value.
Defines a handle_keyword/4
callback that will return :ignore
for the
given keyword. The keyword must be given in atom form.
Adds the given integer to the list accumulator as a 2-tuple with the given
key
.
An utility macro to ease declare vocabularies with atom keys.
Adds the given integer to the list accumulator as a 2-tuple with the given
key
.
Gives the sub raw schema to the builder and adds the build result in the list
accumulator as a 2-tuple with the given key
.
Types
@type acc() :: term()
Represents the accumulator initially returned by init_validators/1
and
accepted and returned by handle_keyword/4
.
This accumulator is then given to finalize_validators/1
and the
collection/0
type is used from there.
@type collection() :: term()
Represents the final form of the collected keywords after the ultimate
transformation returned by finalize_validators/1
.
Callbacks
@callback finalize_validators(acc()) :: :ignore | collection()
@callback format_error(atom(), %{optional(atom()) => term()}, data()) :: String.t() | {String.t(), [JSV.Validator.Error.t() | JSV.ErrorFormatter.annotation()]} | {atom(), String.t(), [JSV.Validator.Error.t() | JSV.ErrorFormatter.annotation()]}
@callback handle_keyword(pair(), acc(), JSV.Builder.t(), raw_schema :: term()) :: {:ok, acc(), JSV.Builder.t()} | :ignore | {:error, term()}
@callback priority() :: pos_integer()
Returns the priority for applyting this module to the data.
Lower values (close to zero) will be applied first. You can think "order" instead of "priority" but several modules can share the same priority value.
This can be useful to define vocabularies that depend on other vocabularies.
For instance, the unevaluatedProperties
keyword needs "properties",
"patternProperties", "additionalProperties" and "allOf", "oneOf", "anyOf",
etc. to be ran before itself so it can lookup what has been evaluated.
Modules shipped in this library have priority of 100, 200, etc. up to 900 so you can interleave your own vocabularies. Casting values to non-validable terms (such as structs or dates) should be done by vocabularies with a priority of 1000 and above.
@callback validate(data(), collection(), JSV.Validator.context()) :: JSV.Validator.result()
Functions
By using this module you will:
- Declare that module as a behaviour
- Import all macros from the module
- Declare a
priority/0
function if the:priority
option is provided.
Defines a handle_keyword/4
callback that will return the current
accumulator without changes, but preventing other vocabulary modules with
lower priority (higher number) to be called with this keyword.
The keyword must be given in atom form.
Defines a handle_keyword/4
callback that will return :ignore
for any
given value.
Generally used below take_keyword/6
:
take_keyword :items, items when is_map(items), acc, builder, raw_schema do
# ...
end
ignore_any_keyword()
Defines a handle_keyword/4
callback that will return :ignore
for the
given keyword. The keyword must be given in atom form.
Generally used below take_keyword/6
:
take_keyword :items, items when is_map(items), acc, builder, raw_schema do
# ...
end
ignore_keyword(:additionalItems)
ignore_keyword(:prefixItems)
@spec take_integer( JSV.Validator.path_segment(), integer() | term(), list(), JSV.Builder.t() ) :: {:ok, list(), JSV.Builder.t()} | {:error, binary()}
Adds the given integer to the list accumulator as a 2-tuple with the given
key
.
Fails if the value is not an integer. Floats with zero-fractional (as 123.0
)
will be accepted and converted to integer, as the JSON Schema spec dictates.
An utility macro to ease declare vocabularies with atom keys.
Defines the handle_keyword/4
callback.
Important
The keyword must be given in atom form.
The original goal was to allow atom keys and values everywhere. Schemas are now converted to binary from before being built.
It is still useful to use this macro to the signature of the
handle_keyword/4
callback can be changed easily without too much refactoring.Guards must be placed after the second argument:
take_keyword :items, items when is_map(items), acc, builder, raw_schema do # ... end
@spec take_number( JSV.Validator.path_segment(), number() | term(), list(), JSV.Builder.t() ) :: {:ok, list(), JSV.Builder.t()} | {:error, binary()}
Adds the given integer to the list accumulator as a 2-tuple with the given
key
.
Fails if the value is not a number.
@spec take_sub( JSV.Validator.path_segment(), JSV.Builder.raw_schema() | term(), list(), JSV.Builder.t() ) :: {:ok, list(), JSV.Builder.t()} | {:error, term()}
Gives the sub raw schema to the builder and adds the build result in the list
accumulator as a 2-tuple with the given key
.