jeromedoyle

jeromedoyle

JSON API response to Structs using Ecto Schema

Does anyone have an example of using Ecto Schemas for parsing JSON api responses?
I’m curious how you can convert this

{
    "id": 283230,
    "fname": "John",
    "lname": "Smith",
    "email": "john.smith@example.com",
    "createdOn": "2016-03-31T10:49:11.386-05:00",
    "updatedOn": "2016-10-31T16:36:12.968-05:00",
    "_embedded": {
      "addresses": [
        {
          "city": "Minneapolis",
          "state": "MN"
        },
        {
          "city": "New Orleans",
          "state": "LA"
        }
      ]
    }
}

into this

%User{
  id: 283230,
  fname: "John",
  lname: "Smith",
  email: "john.smith@example.com",
  createdOn: "2016-03-31T10:49:11.386-05:00",
  updatedOn: "2016-10-31T16:36:12.968-05:00",
  addresses: [
    %Address{
      "city": "Minneapolis",
      "state": "MN"
    },
    %Address{
      "city": "New Orleans",
      "state": "LA"
    }
  ]
}

First Post!

NobbZ

NobbZ

Poison and its protocols are designed for this.

There might be alternatives available, but poison is in phoenix by default.

Most Liked

IvanR

IvanR

One alternative valid way is to use Jason and plain structs with @type t :: ... definitions plus Domo for validation.

Considering MapShaper module from this example app, the structs can be defined like:

defmodule Address do
  @moduledoc false

  use Domo

  defstruct [city: "", state: ""]

  @type t :: %__MODULE__{city: String.t(), state: String.t()}
end

defmodule User do
  @moduledoc false

  use Domo

  today = NaiveDateTime.utc_now()
  defstruct [id: 0, fname: "", lname: "", email: "", createdOn: today, updatedOn: today, addresses: [%Address{}]]

  @type t :: %__MODULE__{
    id: non_neg_integer(),
    fname: String.t(),
    lname: String.t(),
    email: String.t(),
    createdOn: NaiveDateTime.t(),
    updatedOn: NaiveDateTime.t(),
    addresses: [Address.t()]
  }

  defimpl MapShaper.Target do
    def translate_source_map(_value, map) do
      addresses = get_in(map, ["_embedded", "addresses"])
      created_on = map |> get_in(["createdOn"]) |> parse_date()
      updated_on = map |> get_in(["updatedOn"]) |> parse_date()

      map
      |> Map.put("addresses", addresses)
      |> Map.put("createdOn", created_on)
      |> Map.put("updatedOn", updated_on)
    end

    defp parse_date(str) do
      str
      |> NaiveDateTime.from_iso8601()
      |> then(fn
        {:ok, date_time} -> date_time
        _ -> nil
      end)
    end
  end
end

And parsing + validation that looks like:

with {:ok, binary} <- File.read("user.json"),
      {:ok, map} <- Jason.decode(binary),
      user = MapShaper.from_map(%User{}, map),
      {:ok, user} <- User.ensure_type_ok(user) do
  user
end

Returns the following nested struct for the valid input:

%User{
  id: 283230,
  fname: "John",
  lname: "Smith",
  email: "john.smith@example.com",
  createdOn: ~N[2016-03-31 10:49:11.386],
  updatedOn: ~N[2016-10-31 16:36:12.968],
  addresses: [
    %Address{city: "Minneapolis", state: "MN"},
    %Address{city: "New Orleans", state: "LA"}
  ]
}

Where Next?

Popular in Questions Top

ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement