IvanR

IvanR

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 and from_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:

Run in Livebook

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:

Showing Posts 1 to 7

IvanR

IvanR OP

0.1.1 - November 13, 2021

  • Add has_key?/2 and get/3 map functions that lookup keys in maps both in a binary or an atom form.

  • Add the link to open Readme.md in LiveBook :slightly_smiling_face:

dimitarvp

dimitarvp

I needed exactly this two weeks ago, thanks for making it. :heart:

dredison

dredison

This is 100% exactly the library I needed. Thank you! (and again the extra time you spent on the documentation).

IvanR

IvanR OP

0.2.0 - August 16, 2022

  • Fix to ensure the module is loaded before checking if it’s a struct
  • Add decode and encode verbs to function names
  • Support [Module] hint in the map returned from from_map_hint to decode the list of structs
  • Support %{one_key: :other_key} mapping configuration for the PreDecoder protocol in @derive attribute.

Now, for most common decoding cases, it’s possible to configure decoding fully in a declarative way by providing param maps when deriving protocols like that:

defmodule Order do
  @derive [
    {Nestru.PreDecoder, %{"attrs" => :total}},
    {Nestru.Decoder, %{total: Total}}
  ]

  defstruct [:id, :total]
end

defmodule Total do
  @derive Nestru.Decoder
  
  defstruct [:sum]
end

so the decoding works like that:

Nestru.decode_from_map(%{"attrs" => %{"sum" => 568}, "id" => "A874"}, Order)

{:ok, %Order{id: "A874", total: %Total{sum: 568}}}
IvanR

IvanR OP

0.2.1 - August 20, 2022

  • Fix decode_from_map(!)/2/3 to return the error for not a map value
IvanR

IvanR OP

0.3.0 - November 14, 2022

  • Rename Nestru.PreDecoder.gather_fields_map/3 to gather_fields_from_map/3
  • Rename Nestru.Encoder.encode_to_map/1 to Nestru.Encoder.gather_fields_from_struct/2
  • Make encode_to_map(!)/2 work only with structs and add encode_to_list_of_maps(!)/2 for lists
  • Add context parameter to encode_to_* functions

Contexts can be helpful to specify Decoder or Encoder strategy for various senders or receivers of the map.

That is the Nestru.decode_from_map(map, Item, :mobile) call passes :mobile context to def from_map_hint(value, context, map) and the Nestru.encode_to_map(struct, :mobile) call passes the :mobile context to def gather_fields_from_struct(%Item{} = struct, context) implementation for the Item struct appropriately.

So the application’s internal model can be translated into several inbound and outbound models depending on the context :slightly_smiling_face:

IvanR

IvanR OP

0.3.1 - November 22, 2022

  • Add :only and :except options for deriving of Nestru.Encoder protocol (hommage for Jason.Encoder approach :slightly_smiling_face:)
  • Add explicit :translate option for deriving of Nestru.PreDecoder protocol
  • Add explicit :hint option for deriving of Nestru.Decoder protocol

See the documentation for examples.

— All posts loaded —

Where Next? Top

Trending in Announcing Top

wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
fuelen
Hi all! I want to present a small library which provides a mix task for generating an Entity-Relationship Diagram for Ecto schemas. You...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
AstonJ
This showed up on my feed.. anyone heard of it? Just hype? Ox Alpha is a reasoning model designed for coding, sustained ag...
New
sergio
It’s not that it’s vocabulary is too advanced. It’s something worse. I get lost trying to follow even a paragraph written by Claude. It’...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
akoutmos
@hugobarauna, Dr. Dimitrios Koutmos (my brother) and I (Alex Koutmos) have been hard at work on writing a book on how you can use Elixir ...
New
pferriby
Introductory paragraph I’ll be looking for a keen junior or someone that has a couple of years experience in the real world (so you’ve be...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews