defmodule Salemove.HttpClient.Decoder do @moduledoc """ A module, responsible for creating a `EngagementRouter.HttpClient.Response` from `Tesla` response, or, if request wasn't successful, for creating one of exception structures. """ alias Salemove.HttpClient.Response alias Salemove.HttpClient.JSONError alias Salemove.HttpClient.ConnectionError alias Salemove.HttpClient.UnexpectedRedirectError alias Salemove.HttpClient.ClientError alias Salemove.HttpClient.ServerError alias Salemove.HttpClient.UnavailableError alias Salemove.HttpClient.UnsupportedProtocolError @type tesla_result :: {:ok, Tesla.Env.t()} | {:error, reason :: any} @type on_decode :: {:ok, Response.t()} | {:error, reason} @type reason :: JSONError.t() | ConnectionError.t() | UnexpectedRedirectError.t() | ClientError.t() | ServerError.t() | UnavailableError.t() | UnsupportedProtocolError.t() @doc """ Accepts result of request to `Tesla` client and constructs `#{Response}` structure from it. """ @spec decode(tesla_result) :: on_decode def decode(tesla_result) def decode({:ok, %Tesla.Env{} = env}) do decode_env(env) end def decode({:error, {Tesla.Middleware.JSON, :decode, %Jason.DecodeError{} = error}}) do decode_error(error) end def decode({:error, reason}) do decode_error(reason) end ## defp decode_env(%{status: status} = env) do cond do status in 200..299 -> {:ok, Response.new(env)} status in 300..399 -> {:error, UnexpectedRedirectError.new(env)} status in 400..499 -> {:error, ClientError.new(env)} status in 500..501 -> {:error, ServerError.new(env)} status > 501 -> {:error, UnavailableError.new(env)} true -> {:error, UnsupportedProtocolError.new(env)} end end defp decode_error(%Jason.DecodeError{} = error) do {:error, %JSONError{reason: Exception.message(error)}} end defp decode_error(reason) do {:error, %ConnectionError{reason: reason}} end end