defmodule ExIsbndb.Client do @moduledoc """ The `ExIsbndb.Client` module is in charge of creating and sending requests to the ISBNdb API. """ @base_url %{ basic: "https://api2.isbndb.com/", premium: "https://api.premium.isbndb.com/", pro: "https://api.pro.isbndb.com/" } @doc """ Builds and sends a request to the ISBNdb API. Accepts `:get` and `:post` methods. ## Examples iex> ExIsbndb.Client.request(:get, "author/{author_name}") {:ok, %Finch.Reponse{body: "json_string", headers: [...], status: 200}} """ @spec request(:get | :post, binary(), map()) :: {:ok, Finch.Response.t()} | {:error, any()} def request(method, path, params \\ %{}) when is_map(params) and is_binary(path) do method |> build_request(path, params) |> Finch.request(IsbnFinch) end ########## ## PRIV ## ########## # Builds the Finch request defp build_request(:get, path, params), do: Finch.build(:get, build_url(path, params), headers()) defp build_request(:post, path, params), do: Finch.build(:post, build_url(path), headers(), Jason.encode_to_iodata!(params)) defp build_request(method, _path, _params), do: raise( ArgumentError, "unsupported method #{inspect(method)}. Supported methods `:get`, `:post`" ) # Builds the URL with the query params if needed defp build_url(path), do: base_url() <> path defp build_url(path, params), do: base_url() <> path <> "?" <> URI.encode_query(params) # Returns the required HTTP headers defp headers, do: [{"Authorization", api_key()}] # Fetches the ISBNdb API key defp api_key do case Application.fetch_env!(:ex_isbndb, :api_key) do key when is_binary(key) -> key key -> raise KeyError, "unsupported API Key #{inspect(key)}. Must be a binary value." end end # Returns the base URL based on the ISBNdb plan defp base_url do plan = Application.fetch_env!(:ex_isbndb, :plan) case Map.fetch(@base_url, plan) do :error -> raise KeyError, "unsupported plan #{inspect(plan)}. Supported plans `:basic`, `:premium`, `:pro`" {:ok, url} -> url end end end