The Nestru library can convert a map of any shape into a model of nested structs according to given hints. And It can convert any nested struct into a map.
The library’s primary purpose is to serialize between JSON map and an application’s model that is a struct having other structs nested in it.
It comes from the idea to have no DSL and less custom code to parse JSONs as an alternative to full-fledged Ecto with schemaless changesets.
Works good in Jason <-> Nestru
pair.
There are several possible data validation options:
- with ex_json_schema applied to the map before passing to Nestru
- within Nestru
gather_fields_map/3
andfrom_map_hint/3
callbacks - with Ecto schemaless changesets applied to the struct
- with Domo applied to the struct to validate the struct conformance to its
@type t()
and associated preconditions
See typical usage in Readme.md via:
Shortly it looks like:
defmodule Order do
@derive [
Nestru.Encoder,
{Nestru.Decoder, %{items: [LineItem], total: Total}}
]
# Gave a hint to Nestru on how to process the items and total fields
# others go to a struct as is.
defstruct [:id, :items, :total]
end
defmodule LineItem do
@derive [Nestru.Encoder, Nestru.Decoder]
defstruct [:amount]
end
defmodule Total do
@derive [Nestru.Encoder, Nestru.Decoder]
defstruct [:sum]
end
map = %{
"id" => "A548",
"items" => [%{"amount" => 150}, %{"amount" => 350}],
"total" => %{"sum" => 500}
}
{:ok, model} = Nestru.decode_from_map(map, Order)
returns:
{:ok,
%OrderA{
id: "A548",
items: [%LineItemA{amount: 150}, %LineItemA{amount: 350}],
total: %Total{sum: 500}
}}
And going back to the map is as simple as that:
map = Nestru.encode_to_map(model)
returns:
%{
id: "A548",
items: [%{amount: 150}, %{amount: 350}],
total: %{sum: 500}
}
More information here: