Composable data codecs, schemas, and validation for Elixir.
Formata decodes and encodes JSON, TOML, and YAML, validates data against
native (Formata.Backplane.Schema) schemas or JSON Schema documents
(Formata.Backplane.JsonSchema), and applies explicit transformations.
iex> {:ok, schema} = Formata.Schema.native(%{"port" => {:required, {:integer, gte: 1}}})
iex> {:ok, data} = Formata.decode(~s({"port": 8080}), :json)
iex> Formata.validate(data, schema)
:ok
iex> Formata.encode(data, :toml)
{:ok, "port = 8080\n"}Conventions
- Data-first arguments:
decode(input, format),encode(data, format),convert(input, from, to),validate(data, schema),cast(data, schema). - Producing operations return
{:ok, result};validate/3returns:ok. - Expected failures return
{:error, errors}with a non-empty list ofFormata.Errorstructs.
Summary
Functions
Validates and transforms data with a native schema.
Converts a document from one format to another.
Decodes a document.
Encodes data as a document.
Validates data against a compiled schema without changing it.
Types
@type errors() :: [Formata.Error.t(), ...]
@type format() :: Formata.Codec.format()
Functions
@spec cast(term(), Formata.Schema.t(), keyword()) :: {:ok, term()} | {:error, errors()}
Validates and transforms data with a native schema.
Applies the schema's defaults, coercions, and transforms, and handles unknown
fields per unknown: :strip | :allow | :reject (default :strip). See
Formata.Schema.Native for the order of operations. Returns {:ok, data}.
JSON Schemas define no transformations, so casting with one returns an
:unsupported error.
iex> {:ok, schema} = Formata.Schema.native(%{"page" => {:coerce, :integer}})
iex> Formata.cast(%{"page" => "2"}, schema)
{:ok, %{"page" => 2}}
Converts a document from one format to another.
The document is decoded into Elixir values, the optional :transforms are
applied in order (see Formata.Transform.apply_all/2), and the result is
encoded. No intermediate format is used.
Options
:transforms- explicit transformations, for example[:drop_nils]:decode- options for the source codec:encode- options for the target codec
Examples
iex> Formata.convert(~s({"name": "Ada", "nick": null}), :json, :toml, transforms: [:drop_nils])
{:ok, ~s(name = "Ada"\n)}
iex> {:error, [%Formata.Error{kind: :encode, code: :unrepresentable}]} =
...> Formata.convert(~s({"nick": null}), :json, :toml)
Decodes a document.
format is :json, :toml, :yaml, or a Formata.Codec module; opts
are passed to the codec.
iex> Formata.decode("name: Ada", :yaml)
{:ok, %{"name" => "Ada"}}
iex> {:error, [%Formata.Error{kind: :parse, code: :syntax}]} = Formata.decode("{", :json)
Encodes data as a document.
Values the target format cannot represent are rejected with :encode errors;
nothing is dropped or converted implicitly.
iex> Formata.encode(%{"a" => [1, 2]}, :json)
{:ok, ~s({"a":[1,2]})}
iex> {:error, [%Formata.Error{kind: :encode, code: :unrepresentable, path: ["a"]}]} =
...> Formata.encode(%{"a" => nil}, :toml)
@spec validate(term(), Formata.Schema.t(), keyword()) :: :ok | {:error, errors()}
Validates data against a compiled schema without changing it.
No coercion, defaults, or field stripping happen; the data is checked as
given. Returns :ok or {:error, errors}.
Options
unknown: :allow | :reject- native schemas only (default:allow). JSON Schemas accept no options; their ownadditionalProperties/unevaluatedPropertiesapply.
Examples
iex> {:ok, schema} = Formata.Schema.native(%{age: :integer})
iex> Formata.validate(%{"age" => 30}, schema)
:ok
iex> {:error, [%Formata.Error{kind: :validation, code: :type, path: ["age"]}]} =
...> Formata.validate(%{"age" => "30"}, schema)