defmodule LoopsEx.Client do @moduledoc """ HTTP client for Loops API. """ @typedoc "Response type returned by Loops API calls" @type response :: {:ok, any()} | {:error, any()} @typedoc "Raw JSON map returned from API" @type json :: map() use Tesla @base_url "https://app.loops.so/api/v1" @doc """ Build a Tesla client for the Loops API. """ @spec client() :: Tesla.Client.t() def client do api_key = Application.get_env(:loops_ex, :api_key) middleware = [ {Tesla.Middleware.BaseUrl, @base_url}, {Tesla.Middleware.BearerAuth, token: api_key}, {Tesla.Middleware.JSON, engine: Jason} ] Tesla.client(middleware) end @doc """ Execute an API call. - method: HTTP method atom (e.g. :get, :post) - path: endpoint path (e.g. "/contacts/create") - body: JSON body map (default %{}) - query: query params map (default %{}) Returns `response()` tuple. """ @spec request_api(atom(), String.t(), json(), map()) :: response() def request_api(method, path, body \\ %{}, query \\ %{}) do Tesla.request(client(), method: method, url: path, body: body, query: query) end @doc false @spec handle_response({:ok, Tesla.Env.t()} | {:error, any()}) :: response() def handle_response({:ok, %Tesla.Env{status: status, body: body}}) when status >= 200 and status < 300, do: {:ok, body} def handle_response({:ok, %Tesla.Env{status: status, body: body}}), do: {:error, {status, body}} def handle_response({:error, reason}), do: {:error, reason} end