edantic
edantic copied to clipboard
JSON casting and validation library based on Elixir type specifications
Edantic
Edantic is a library for casting «plain» JSON-originated data into Elixir data structures with nessesary validations.
Example
Assume there is a module with a corresponding struct:
defmodule Person do
defstruct [
:age, :name, :department
]
@type first_name() :: String.t
@type second_name() :: String.t
@type t() :: %__MODULE__{
age: non_neg_integer(),
name: {first_name(), second_name()},
department: :finance | :it
}
end
And there is some JSON-originated data:
data = %{
"age" => 23,
"name" => ["girolamo", "savonarola"],
"department" => "it"
}
With Edantic we can simultaneously validate this data and convert it into Elixir structures:
import Edantic
{:ok, person} = Edantic.cast(Person.t(), data)
person == %Person{
age: 23,
name: {"girolamo", "savonarola"},
department: :it
}
data_bad_department = %{
"age" => 23,
"name" => ["girolamo", "savonarola"],
"department" => "unknown"
}
{:error, error} = Edantic.cast(Person.t(), data_bad_department)
error
|> Edantic.CastError.format()
|> IO.puts()
key-value pair does not match to any of the specified for the map
data: %{"department" => "unknown"}
type: %Edantic.Support.Types.Person{age: non_neg_integer(), department: :finance | :it, name: {first_name(), second_name()}}}
JSON
By «JSON-originated data» is denoted all the data matching the following type t():
@type key() :: String.t()
@type value() ::
String.t() | nil | boolean | integer() | float() | %{optional(key()) => value()} | [value()]
@type t() :: value()
Primitive convertions
Since plain data structures are rather poor, there are some automatic enrichments allowed while casting:
- Strings can be casted to corresponding atoms
"a" -> :a. - Lists of suitable size can be casted to tuples
[1, "a"] -> {1, :a}. - Maps can be casted to arbitrary struct whith the same set of fields
%{a: 123} -> %SomeSt{a: 123}if fields pass validations.
Usage in releases
Since type info is located in seperate beam chunks which are stripped by default, be sure your releases do not strip them.
For example, by setting strip_beams option to false.
def project do
[
...
deps: deps(),
releases: [
release_name: [
strip_beams: false,
...
]
]
]
end
Installation
If available in Hex, the package can be installed
by adding edantic to your list of dependencies in mix.exs:
def deps do
[
{:edantic, "~> 0.1.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/edantic.
License
This software is licensed under MIT License.