View Source Xema (xema v0.16.0)
A schema validator inspired by JSON Schema.
All available keywords to construct a schema are described on page Usage.
This module can be used to construct a schema module. Should a module
contain multiple schemas the option multi: true
is required.
use Xema
imports Xema.Builder
and extends the module with the functions
__MODULE__.valid?/2
__MODULE__.validate/2
__MODULE__.validate!/2
__MODULE__.cast/2
__MODULE__.cast!/2
__MODULE__.xema/1
The macro xema/2
supports the construction of a schema. After that
the schema is available via the functions above.
In a multi schema module a schema can be tagged with the option
default: :schema_name
and then called by
__MODULE__.valid?/1
__MODULE__.validate/1
__MODULE__.validate!/1
__MODULE__.cast/1
__MODULE__.cast!/1
__MODULE__.xema/0
The functions with arity 1 are also available for single schema modules.
The macro xema_struct/1
creates a schema with the coresponding struct.
examples
Examples
Single schema module:
iex> defmodule SingleSchema do
...> use Xema
...>
...> # The name :num is optional.
...> xema :num, do: number(minimum: 1)
...> end
iex>
iex> SingleSchema.valid?(:num, 6)
true
iex> SingleSchema.valid?(5)
true
iex> SingleSchema.validate(0)
{:error, %Xema.ValidationError{
reason: %{minimum: 1, value: 0}
}}
iex> SingleSchema.cast("5")
{:ok, 5}
iex> SingleSchema.cast("-5")
{:error, %Xema.ValidationError{
reason: %{minimum: 1, value: -5}
}}
Multi schema module:
iex> defmodule Schema do
...> use Xema, multi: true, default: :user
...>
...> @pos integer(minimum: 0)
...> @neg integer(maximum: 0)
...>
...> xema :user do
...> map(
...> properties: %{
...> name: string(min_length: 1),
...> age: @pos
...> }
...> )
...> end
...>
...> xema :nums do
...> map(
...> properties: %{
...> pos: list(items: @pos),
...> neg: list(items: @neg)
...> }
...> )
...> end
...> end
iex>
iex> Schema.valid?(:user, %{name: "John", age: 21})
true
iex> Schema.valid?(%{name: "John", age: 21})
true
iex> Schema.valid?(%{name: "", age: 21})
false
iex> Schema.validate(%{name: "John", age: 21})
:ok
iex> Schema.validate(%{name: "", age: 21})
{:error, %Xema.ValidationError{
reason: %{
properties: %{name: %{min_length: 1, value: ""}}}
}
}
iex> Schema.valid?(:nums, %{pos: [1, 2, 3]})
true
iex> Schema.valid?(:nums, %{neg: [1, 2, 3]})
false
Struct schema module:
iex> defmodule StructA do
...> use Xema
...>
...> xema_struct do
...> field :foo, :integer, minimum: 0
...> end
...> end
...>
...> defmodule StructB do
...> use Xema
...>
...> xema_struct do
...> field :a, :string, min_length: 3
...> field :b, StructA
...> required [:a]
...> end
...> end
...>
...> data = StructB.cast!(a: "abc", b: %{foo: 5})
...> data.a
"abc"
iex> Map.from_struct(data.b)
%{foo: 5}
For more examples to construct schemas see "Examples".
Link to this section Summary
Types
The return type of a validation run.
This struct contains the schema and references of the schema.
Functions
Converts the given data using the specified schema. Returns the converted data or an exception.
Converts the given data using the specified schema. Returns {:ok, result}
or
{:error, reason}
. The result
is converted and validated with the schema.
Creates a Xema
from a JSON Schema. The argument json_schema
is expected
as a decoded JSON Schema.
This function creates the schema from the given data
.
Returns the source for a given xema
. The output can differ from the input
if the schema contains references. To get the original source the schema
must be created with inline: false
.
Returns true
if the value
is a valid value against the given schema
;
otherwise returns false
.
Returns :ok
if the value
is a valid value against the given schema
;
otherwise raises a Elixir.Xema.ValidationError
. See validate3
for
available options.
Returns :ok
if the value
is a valid value against the given schema
;
otherwise returns an error tuple.
Link to this section Types
@type result() :: Xema.Validator.result()
The return type of a validation run.
@type schema() :: Xema.Schema.t()
@type t() :: %Xema{refs: map(), schema: Xema.Schema.t()}
This struct contains the schema and references of the schema.
Link to this section Functions
Converts the given data using the specified schema. Returns the converted data or an exception.
Converts the given data using the specified schema. Returns {:ok, result}
or
{:error, reason}
. The result
is converted and validated with the schema.
examples
Examples:
iex> schema = Xema.new({:integer, minimum: 1})
iex> Xema.cast(schema, "5")
{:ok, 5}
iex> Xema.cast(schema, "five")
{:error, %Xema.CastError{
key: nil,
path: [],
to: :integer,
value: "five"
}}
iex> Xema.cast(schema, "0")
{:error, %Xema.ValidationError{
reason: %{minimum: 1, value: 0}
}}
multiple-types
Multiple types
If for a value multiple types are defined the function used the result of the first successful conversion.
examples-1
Examples
iex> schema = Xema.new([:integer, :string, nil])
iex> Xema.cast(schema, 5)
{:ok, 5}
iex> Xema.cast(schema, 5.5)
{:ok, "5.5"}
iex> Xema.cast(schema, "5")
{:ok, 5}
iex> Xema.cast(schema, "five")
{:ok, "five"}
iex> Xema.cast(schema, nil)
{:ok, nil}
iex> Xema.cast(schema, [5])
{:error,
%Xema.CastError{path: [], to: [:integer, :string, nil], value: [5]}
}
cast-with-any_of-all_of-and-one_of
Cast with any_of
, all_of
, and one_of
Schemas in a combiner will be cast independently one by one in reverse order.
examples-2
Examples
iex> schema = Xema.new(any_of: [
...> [properties: %{a: :integer}],
...> [properties: %{a: :string}]
...> ])
iex> Xema.cast(schema, %{a: 5})
{:ok, %{a: 5}}
iex> Xema.cast(schema, %{a: 5.5})
{:ok, %{a: "5.5"}}
iex> Xema.cast(schema, %{a: "5"})
{:ok, %{a: 5}}
iex> Xema.cast(schema, %{a: "five"})
{:ok, %{a: "five"}}
iex> Xema.cast(schema, %{a: [5]})
{:error,
%Xema.CastError{
error: nil,
key: nil,
message: nil,
path: [],
to: [
%{path: [:a], to: :integer, value: [5]},
%{path: [:a], to: :string, value: [5]}
],
value: %{a: [5]}
}}
options
Options
With the option additional_properties: :delete
additional properties will be
deleted on cast. Additional properties will be deleted in schemas with
additional_properties: false
.
examples-3
Examples
iex> schema = Xema.new(
...> properties: %{
...> a: [
...> properties: %{
...> foo: :integer
...> },
...> additional_properties: false
...> ],
...> b: [
...> properties: %{
...> foo: :integer
...> }
...> ]
...> }
...> )
iex>
iex> Xema.cast(schema, %{
...> a: %{foo: "6", bar: "7"},
...> b: %{foo: "6", bar: "7"},
...> }, additional_properties: :delete)
{:ok, %{
a: %{foo: 6},
b: %{foo: 6, bar: "7"}
}}
Creates a Xema
from a JSON Schema. The argument json_schema
is expected
as a decoded JSON Schema.
All keys that are not standard JSON Schema keywords have to be known atoms. If
the schema has additional keys that are unknown atoms the option
atom: :force
is needed. In this case the atoms will be created. This is not
needed for keys expected by JSON Schema (e.g. in properties)
Options:
:draft
specifies the draft to check the given JSON Schema. Possible values are"draft4"
,"draft6"
, and"draft7"
, default is"draft7"
. If:draft
not set and the schema contains$schema
then the value for$schema
is used for this option.:atoms
creates atoms for unknown atoms when set to:force
. This is just needed for additional JSON Schema keywords.
examples
Examples
iex> Xema.from_json_schema(%{"type" => "integer", "minimum" => 5})
%Xema{schema: %Xema.Schema{minimum: 5, type: :integer}}
iex> schema = %{
...> "type" => "object",
...> "properties" => %{"foo" => %{"type" => "integer"}}
...> }
iex> Xema.from_json_schema(schema)
%Xema{schema:
%Xema.Schema{
properties: %{"foo" => %Xema.Schema{type: :integer}},
type: :map,
keys: :strings
}
}
iex> Xema.from_json_schema(%{"type" => "integer", "foo" => "bar"}, atom: :force)
%Xema{schema: %Xema.Schema{data: %{foo: "bar"}, type: :integer}}
iex> Xema.from_json_schema(%{"exclusiveMaximum" => 5}, draft: "draft7")
%Xema{schema: %Xema.Schema{exclusive_maximum: 5}}
iex> Xema.from_json_schema(%{"exclusiveMaximum" => 5}, draft: "draft4")
** (Xema.SchemaError) Can't build schema:
Dependencies for "exclusiveMaximum" failed. Missing required key "maximum".
@spec new( Xema.Schema.t() | Xema.Schema.type() | tuple() | atom() | keyword(), keyword() ) :: t()
This function creates the schema from the given data
.
Possible options:
:loader
- a loader for remote schemas. This option will overwrite theloader from the config. See [Configure a loader](loader.html) to how to define a loader.
inline
- inlined all references in the schema. Default:true
.
examples
Examples
Simple schema:
iex> schema = Xema.new :string
iex> Xema.valid? schema, "hello"
true
iex> Xema.valid? schema, 42
false
Schema:
iex> schema = Xema.new {:string, min_length: 3, max_length: 12}
iex> Xema.valid? schema, "hello"
true
iex> Xema.valid? schema, "hi"
false
Nested schemas:
iex> schema = Xema.new {:list, items: {:number, minimum: 2}}
iex> Xema.validate(schema, [2, 3, 4])
:ok
iex> Xema.valid?(schema, [2, 3, 4])
true
iex> Xema.validate(schema, [2, 3, 1])
{:error, %Xema.ValidationError{
reason: %{
items: %{2 => %{value: 1, minimum: 2}}}
}
}
More examples can be found on page Usage.
Returns the source for a given xema
. The output can differ from the input
if the schema contains references. To get the original source the schema
must be created with inline: false
.
examples
Examples
iex> {:integer, minimum: 1} |> Xema.new() |> Xema.source()
{:integer, minimum: 1}
Returns true
if the value
is a valid value against the given schema
;
otherwise returns false
.
Returns :ok
if the value
is a valid value against the given schema
;
otherwise raises a Elixir.Xema.ValidationError
. See validate3
for
available options.
Returns :ok
if the value
is a valid value against the given schema
;
otherwise returns an error tuple.
With the option :fail
, you can define when the validation is aborted. This
also influences how many error reasons are returned.
:immediately
aborts the validation when the first validation fails.:early
(default) aborts on failed validations, but runs validations for all properties and items.:finally
aborts after all possible validations.