Question about Poison.decode

defmodule Bitly.Link do

  def shorten(long_url, opts \\ [], client \\ Client.new()) do
    get_response_body(client, "/shorten", Keyword.merge([longUrl: long_url], opts))
  end

  defp get_response_body(client, path, query) do
    client
    |> Client.get(path, query: query)
    |> handle_response_body()
  end

  defp handle_response_body(%{body: body}) do
    case Poison.decode(body, as: %__MODULE__{}) do
      {:ok, result} -> result
      {:error, _} -> body
    end
  end
end

In this module handle_response_body returns %Bitly.Link{ }.

But I want to refactor last two private function to Helper module like this

defmodule Bitly.Helpers do
  alias Bitly.Client

  def get_response_body(client, path, query, module) do
    {:ok, %{body: body}} = Client.get(client, path, query: query)
    handle_response_body(body, module)
  end

  def handle_response_body(body, module) do
    case Poison.decode(body, as: module) do
      {:ok, result} -> result
      {:error, _} -> body
    end
  end
end

So when I call get_response_body in other module

defmodule Bitly.ClickSummary do
  alias Bitly.{Client, Helpers}

  defstruct [:units, :unit, :total_clicks, :unit_reference]

  @type t :: %__MODULE__{
    total_clicks: integer,
    unit: String.t(),
    unit_reference: String.t(),
    units: integer
  }

  @spec click_summary(String.t(), Client.t()) :: t
  def click_summary(bitlink, client \\ Client.new()) do
    Helpers.get_response_body(client, "/bitlinks/#{bitlink}/clicks/summary", [], __MODULE__)
  end

end

I passed “MODULE” to get_response_body and it passes again to handle_response_body.
So I expected the returns like this
%Bitly.ClickSummary {} but it just returns maps %{}

How can I do this?

In the first example you passed in a struct (%__MODULE__{}) in the second one “just” an atom. Try struct(module) as in

case Poison.decode(body, as: struct(module)) do
2 Likes