lib/hui/http/client.ex

defmodule Hui.Http.Client do
  @moduledoc """
  A client behaviour module for handling Solr HTTP requests and responses.

  This module is responsible for dispatching Solr request encapsulated in `t:Hui.Http.t/0` struct.
  It underpins the core functions of `Hui`. Three implementations have been provided:
    - [Erlang httpc](https://erlang.org/doc/man/httpc.html)
    - [HTTPoison](https://github.com/edgurgel/httpoison)
    - [Finch](https://github.com/sneako/finch)

  ### Using other HTTP clients
  `httpc` is used in Hui by default. One of the above HTTP clients may be deployed
  by adding the client as dependency and specificying it via the `http_client` configuration - see below.
  Other HTTP clients may also be used by implementing this behaviour.

  ```
    config :hui,
      http_client: Hui.Http.Clients.Finch
  ```

  Hui.Http.Clients.Finch depends on `Finch`. The dependency needs to be specified in `mix.exs`.
  You might also need to start the client application by specifying it (e.g. `:httpoison`) in
  the `application` section of `mix.exs`.

  ```
    defp deps do
      [
        {:finch, "~> 0.16"}
      ]
    end
  ```

  For Finch (only), you also need to name and
  [start it from your supervision tree](https://github.com/sneako/finch#usage) and
  configure it as below:

  ```ex
    # use the same name specified in the supervision tree
    config :hui, :finch, name: FinchSolr
  ```

  """

  alias Hui.Http

  @before_compile Hui.Http.Clients

  @type http_response :: {:ok, term()} | {:ok, term()}
  @type request :: Http.t()
  @type response :: {:ok, Http.t()} | {:error, Hui.Error.t()}

  @doc """
  Dispatch HTTP request to a Solr endpoint.

  If a client is not set via `c:build_request/3`, the default httpc-based client
  will be used.
  """
  @callback dispatch(request) :: http_response

  @doc """
  For post-dispatch processing such as error handling and parsing Solr documents.
  """
  @callback handle_response(http_response, request) :: response

  ### common functions

  @spec impl() :: module()
  def impl(), do: Application.get_env(:hui, :http_client, Hui.Http.Clients.Httpc)

  @spec dispatch(request) :: response
  def dispatch(request), do: request.client.dispatch(request)

  @spec handle_response(http_response, request) :: response
  def handle_response(resp, request), do: request.client.handle_response(resp, request)
end