defmodule HeliumElixir.BlockchainApi do
use HTTPoison.Base
alias HTTPoison.Response
alias HTTPoison.Error
alias HeliumElixir.BlockchainApi.BlockchainRequestConfig
alias HeliumElixir.BlockchainApi.TakeMinConfig
defp respond({:ok, %Response{body: body, status_code: status_code}}) do
case status_code do
code when code <= 299 ->
response = body |> Jason.decode!()
{:ok, response}
_ ->
{:error, message: "Request failed with status_code #{status_code}", code: status_code}
end
end
defp respond({:error, %Error{reason: reason}}) do
{:error, message: reason, code: -1}
end
def post_json(
%BlockchainRequestConfig{headers: headers, base_url: base_url, path: path},
body \\ %{}
) do
post(base_url <> path, Jason.encode!(body), headers) |> respond()
end
def get_json(
%BlockchainRequestConfig{headers: headers, base_url: base_url, path: path},
params \\ %{}
) do
get(base_url <> path, headers, params: params, follow_redirect: true) |> respond()
end
@doc """
Pages the given endpoint until `min_count` is reached.
The data returned will be at least the amount requested unless no more items exist.
Returns `{:ok, %{"data" => data, "cursor" => cursor}}`.
"""
def take_min(
%BlockchainRequestConfig{} = config,
%TakeMinConfig{min_count: min_count, params: params, acc: acc, cursor: cursor}
) do
case get_json(config, Map.merge(params, %{cursor: cursor})) do
{:ok, %{"data" => data, "cursor" => next_cursor}} ->
next_data = acc ++ data
acc_count = length(next_data)
if(acc_count >= min_count || is_nil(next_cursor)) do
{:ok, %{"data" => next_data, "cursor" => next_cursor}}
else
take_min(config, %TakeMinConfig{
min_count: min_count,
params: params,
acc: next_data,
cursor: next_cursor
})
end
{:ok, %{"data" => data}} ->
{:ok, %{"data" => acc ++ data, "cursor" => ""}}
{:error, message: message, code: code} ->
{:error, message: message, code: code}
end
end
end