defmodule Ehee do use HTTPoison.Base @endpoint "https://api.github.com" def post(path, credential, body \\ "") do url = url(path) request!(:post, url, Poison.encode!(body), authorization_headers(credential.auth, []), []) |> handle_response end def patch(path, credential, body \\ "") do url = url(path) request!(:post, url, Poison.encode!(body), authorization_headers(credential.auth, []), []) |> handle_response end def put(path, credential, body \\ "") do url = url(path) request!(:put, url, Poison.encode!(body), authorization_headers(credential.auth, []), []) |> handle_response end def delete(path, credential, body \\ "") do url = url(path) request!(:delete, url, Poison.encode!(body), authorization_headers(credential.auth, []), []) |> handle_response end def get(path, credential, params \\ [], options \\ []) do url = url(path)# |> merge_uri_params case pagination(options) do :nil -> request_stream(:get, url, credential) :stream -> request_stream(:get, url, credential) end end defp pagination(options) do Keyword.get(options, :pagination, :nil) end defp request_stream(method, url, credential, body \\ "", override \\ nil) do request_with_pagination(method, url, credential.auth, body) |> stream_if_needed(override) end defp stream_if_needed(result = {status_code, _}, _) when is_number(status_code), do: result defp stream_if_needed({body, nil, _}, _), do: body defp stream_if_needed({body, _, _}, :one_page), do: body defp stream_if_needed(initial_results, _) do Stream.resource( fn -> initial_results end, &handle_stream/1, fn _ -> nil end) end def request_with_pagination(method, url, auth, body \\ "") do resp = request!(method, url, Poison.encode!(body), authorization_headers(auth, []), []) case handle_response(resp) do x when is_tuple(x) -> x _ -> pagination_tuple(resp, auth) end end defp handle_stream({[], nil, _}), do: {:halt, nil} defp handle_stream({[], next, auth}) do request_with_pagination(:get, next, auth, "") |> handle_stream end # defp handle_stream({items, next, auth}) when is_list(items) do # {items, {[], next, auth}} # end defp handle_stream({item, next, auth}) do {[item], {[], next, auth}} end defp pagination_tuple(%HTTPoison.Response{headers: headers} = resp, auth) do {handle_response(resp), next_link(headers), auth} end defp next_link(headers) do for {"Link", link_header} <- headers, links <- String.split(link_header, ",") do Regex.named_captures(~r/<(?.*)>;\s*rel=\"(?.*)\"/, links) |> case do %{"link" => link, "rel" => "next"} -> link _ -> nil end end |> Enum.filter(&(not is_nil(&1))) |> List.first end defp merge_uri_params(uri, []), do: uri defp url(path) do @endpoint <> path end def authorization_headers(%{access_token: token}, headers) do headers ++ [{"Authorization", "token #{token}"}] end def handle_response(%HTTPoison.Response{status_code: 200, body: body}), do: body def handle_response(%HTTPoison.Response{status_code: status_code, body: body}), do: { status_code, body } end