defmodule ExDeltaExchange.HTTPClient do alias ExDeltaExchange.JsonResponse @type verb :: :get | :post | :put | :delete @type path :: String.t() @type query_params :: map @type request_body :: String.t() @type credentials :: ExDeltaExchange.Credentials.t() @type error_reason :: Maptu.Extension.non_strict_error_reason() | HTTPoison.Error.t() @type response :: {:ok, JsonResponse.t()} | {:error, error_reason} @spec domain :: String.t() def domain, do: Application.get_env(:ex_delta_exchange, :domain, "api.delta.exchange") @spec protocol :: String.t() def protocol, do: Application.get_env(:ex_delta_exchange, :protocol, "https://") @spec origin :: String.t() def origin, do: protocol() <> domain() @spec url(path) :: String.t() def url(path), do: origin() <> api_path() <> path @spec api_path :: String.t() def api_path, do: Application.get_env(:ex_delta_exchange, :api_path, "/v2") @spec get(path, query_params) :: response def get(path, query_params) do non_auth_request(:get, path, query_params, "") end @spec get(path, query_params, credentials) :: response def get(path, query_params, credentials) do auth_request(:get, path, query_params, "", credentials) end @spec auth_request(verb, path, query_params, request_body, credentials) :: response def auth_request(verb, path, query_params, request_body, credentials) do headers = verb |> auth_headers(path, query_params, request_body, credentials) |> put_content_type(:json) %HTTPoison.Request{ method: verb, url: url(path), headers: headers, body: request_body } |> HTTPoison.request() |> parse_response() end @spec non_auth_request(verb, path, query_params, request_body) :: response def non_auth_request(verb, path, _query_params, request_body) do headers = [] |> put_content_type(:json) %HTTPoison.Request{ method: verb, url: url(path), headers: headers, body: request_body } |> HTTPoison.request() |> parse_response() end defp put_content_type(headers, :json) do Keyword.put(headers, :"Content-Type", "application/json") end defp auth_headers(http_method, path, query_params, request_body, credentials) do normalized_http_method = http_method |> normalize_http_method timestamp = ExDeltaExchange.Auth.timestamp() query_string = URI.encode_query(query_params) signature = ExDeltaExchange.Auth.sign( normalized_http_method, timestamp, api_path() <> path, query_string, request_body, credentials.api_secret ) ["api-key": credentials.api_key, signature: signature, timestamp: timestamp] end defp normalize_http_method(:get), do: "GET" defp normalize_http_method(:post), do: "POST" defp normalize_http_method(:put), do: "PUT" defp normalize_http_method(:delete), do: "DELETE" defp parse_response({:ok, %HTTPoison.Response{body: body}}) do {:ok, json} = Jason.decode(body) Mapail.map_to_struct(json, JsonResponse, transformations: [:snake_case]) end defp parse_response({:error, _} = result) do result end end