View Source Xema (xema v0.17.4)
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
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".
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 {:ok, result}
or
{:error, reason}
. The result
is converted and validated with the schema.
Converts the given data using the specified schema. Returns the converted data or an exception.
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 returns an error tuple.
Returns :ok
if the value
is a valid value against the given schema
;
otherwise raises a Elixir.Xema.ValidationError
. See validate3
for
available options.
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.
Functions
Converts the given data using the specified schema. Returns {:ok, result}
or
{:error, reason}
. The result
is converted and validated with the schema.
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
If for a value multiple types are defined the function used the result of the first successful conversion.
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
Schemas in a combiner will be cast independently one by one in reverse order.
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
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
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"}
}}
Converts the given data using the specified schema. Returns the converted data or an exception.
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.:atom
creates atoms for unknown atoms when set to:force
. This is just needed for additional JSON Schema keywords.
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
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
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 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.
Returns :ok
if the value
is a valid value against the given schema
;
otherwise raises a Elixir.Xema.ValidationError
. See validate3
for
available options.