Creating a Struct with dynamic fields

I have a Struct that I am hydrating from a GraphQL response from Github:

defmodule MyThing.Github.PullRequest do
  defstruct [:title, :approvals] # and a lot of other fields
end

The :approvals fields and some other fields are dynamic based on the content of the response. For example, I’m looping over the reviews for a given pull request. I do that by having a consumer of the request call a from_response method on the struct module:

defmodule PullRequest do
  defstruct [:title, :approvals] # and a lot of other fields

  def from_response(response) do
    struct( __MODULE__, { approvals: approvals(response) })
  end

  defp approvals(response) do
    response["reviews"]
      |> Enum.map(& &1["kind"])
      |> Enum.filter(& &1 == "APPROVAL")
      |> Enum.count
  end
end

The usage would look something like:

pull_requests = GitHubRequest() |> Enum.map(&PullRequest.from_response/1)

The current approach works but feels a little too close to what I would do in Ruby (albeit with a class’s initialize or methods on a struct).

What is the idiomatic way of handling this in Elixir? I’d prefer to have the struct initialized with the correct data one time and not make every consumer of the struct call different methods to calculate the “dynamic” fields.

In my opinion what you have so far seems idiomatic, although I may need to see a little more code to be more sure.

It seems to me that the code you’ve shown accomplishes this goal.

Sometimes it’s fine to write code that is similar to how you would do it in Ruby.