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:

First 7 of 7 Posts Switch mode

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

bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
387 15136 120
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
woylie
Phoenix components for pagination, sortable tables and filter forms with Flop and (optionally) Ecto. pagination cursor pagination sorta...
New
kip
Please say hi to a new lib, Astro that aims to deliver easy-to-consume astronomy calculations of practical use. For now it only calculat...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

Other Trending Topics Top

juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New

We're in Beta

About us Mission Statement