Current section
Files
Jump to
Current section
Files
lib/util/api.ex
defmodule ExOanda.API do
@moduledoc false
alias ExOanda.Connection, as: Conn
alias ExOanda.Telemetry
alias ExOanda.Transform, as: TF
alias ExOanda.TransportError
# Requests ###################################################################
@base_headers [
accept: "application/json",
"user-agent": "ExOanda/" <> Mix.Project.config()[:version]
]
@success_codes Enum.to_list(200..299)
@spec auth_bearer(Conn.t()) :: {:bearer, String.t()}
def auth_bearer(%Conn{token: token}) do
{:bearer, token}
end
@spec base_headers([{atom(), String.t()}]) :: Keyword.t()
def base_headers(opts \\ []), do: Keyword.merge(@base_headers, opts)
# Responses ####################################################################
@spec handle_response({atom(), Req.Response.t() | map()}, atom() | nil) :: {:ok, any()} | {:error, any()}
def handle_response(res, transform_to \\ nil) do
case format_response(res) do
# 2xx status codes
{:ok, fr} -> {:ok, TF.transform(fr, transform_to)}
# Req transport errors
{:error, %Req.TransportError{} = error} -> {:error, TransportError.exception(error)}
# Req HTTP errors
{:error, %Req.HTTPError{} = error} -> {:error, TransportError.exception(error)}
# Req redirect errors
{:error, %Req.TooManyRedirectsError{} = error} -> {:error, TransportError.exception(error)}
# Legacy transport error format (for backward compatibility)
{:error, %{reason: reason}} -> {:error, TransportError.exception(reason)}
# Non-2xx status codes (Oanda API errors)
{:error, fr} -> {:error, TF.transform(fr, transform_to)}
_ -> res
end
end
defp format_response({:ok, %{status: status} = res}) when status in @success_codes, do: {:ok, res}
defp format_response({:ok, res}), do: {:error, res}
defp format_response(res), do: res
# Telemetry ####################################################################
@doc false
defdelegate maybe_attach_telemetry(req, conn), to: Telemetry
end