View Source Cast
Xema
provides the functions Xema.cast/2
and Xema.cast!/2
to convert data according to the
schema. The converted data will also be validated against the schema. The function Xema.cast/2
returns an error tuple with a CastError
when the data cannot be converted.
iex> schema = Xema.new({:integer, minimum: 1})
iex> Xema.cast(schema, "5")
{:ok, 5}
iex> Xema.cast(schema, "-5")
{:error, %Xema.ValidationError{
reason: %{minimum: 1, value: -5}
}}
iex> {:error, error} = Xema.cast(schema, [])
{:error, %Xema.CastError{
key: nil,
path: [],
to: :integer,
value: []
}}
iex> Exception.message(error)
"cannot cast [] to :integer"
With use Xema
the functions are also available.
iex> defmodule Int do
...> use Xema
...>
...> xema do: integer(minimum: 1)
...> end
iex>
iex> Int.cast("6")
{:ok, 6}
iex> Int.cast("-1")
{:error, %Xema.ValidationError{
reason: %{minimum: 1, value: -1}
}}
Maps
To convert map keys the schema has to specify the keys
keyword.
iex> defmodule MapSchema do
...> use Xema
...>
...> xema do
...> map(
...> keys: :atoms,
...> properties: %{
...> pos: integer(minimum: 0),
...> neg: integer(maximum: 0)
...> }
...> )
...> end
...> end
iex>
iex> MapSchema.cast(%{"pos" => "5", "neg" => "-5"})
{:ok, %{pos: 5, neg: -5}}
Caster
To convert "special" structs a caster can be specified. A caster function has to return the
converted value in a tuple {:ok, value}
or an :error
.
iex> defmodule UrisSchema do
...> use Xema
...>
...> def caster(string) when is_binary(string), do: {:ok, URI.parse(string)}
...>
...> def caster(%URI{} = uri), do: {:ok, uri}
...>
...> def caster(_), do: :error
...>
...> xema do
...> map(
...> keys: :atoms,
...> properties: %{
...> uris: list(
...> items: strux(URI, caster: &UrisSchema.caster/1)
...> )
...> }
...> )
...> end
...> end
iex> UrisSchema.cast(%{uris: ["https://hexdocs.pm/elixir/Kernel.html"]})
{:ok, %{uris: [URI.parse("https://hexdocs.pm/elixir/Kernel.html")]}}
The caster can also be a tuple of module and function name or an mfa tuple.
Using Caster
behaviour is also supported.
iex> defmodule UriCaster do
...> @behaviour Xema.Caster
...>
...> @impl true
...> def cast(%URI{} = uri), do: {:ok, uri}
...>
...> def cast(string) when is_binary(string), do: {:ok, URI.parse(string)}
...>
...> def cast(_), do: :error
...> end
iex>
iex> defmodule UriSchema do
...> use Xema
...>
...> xema do
...> map(
...> keys: :strings,
...> properties: %{
...> "uri" => strux(URI, caster: UriCaster)
...> }
...> )
...> end
...> end
iex>
iex> UriSchema.cast(%{uri: "https://elixir-lang.org/docs.html"})
{:ok, %{"uri" => URI.parse("https://elixir-lang.org/docs.html")}}