lib/consul/response.ex

defmodule Consul.Response do
  @moduledoc """
  This module helps decode Tesla responses
  """

  alias Consul.JsonCodec

  @doc """
  Handle the response for a Tesla request

  ## Parameters

    * `response` (*type:* `{:ok, Tesla.Env.t} | {:error, reason}`) - The response object
    * `opts` (*type:* `keyword()`) - [optional] Optional parameters
      *   `:as` (*type:* `module()`) - If present, decode as struct or list.

  ## Returns

    * `{:ok, struct()}` on success
    * `{:error, Tesla.Env.t}` on failure
  """
  @spec decode({:ok, Tesla.Env.t()}, keyword()) :: {:ok, struct()} | {:error, Tesla.Env.t()}
  def decode(env, opts \\ [])

  def decode({:error, reason}, _), do: {:error, reason}

  def decode({:ok, %Tesla.Env{status: status} = env}, _)
      when status < 200 or status >= 300 do
    {:error, env}
  end

  def decode({:ok, %Tesla.Env{body: body} = env}, opts) do
    case Keyword.get(opts, :as) do
      nil ->
        {:ok, env}

      model ->
        case do_decode(body, as: model) do
          {:ok, body} -> {:ok, %{env | body: body}}
          other -> other
        end
    end
  end

  defp do_decode(nil, _opts), do: {:ok, nil}

  defp do_decode(body, opts), do: JsonCodec.decode(body, opts)
end