defmodule Metabase do @moduledoc """ Client used to make HTTP requests. ## Making Requests Requests can be made using the `send/2` function. This function accepts a `Metabase.RequestOperation` struct as the first argument and a keyword list of configuration options as the second argument. ### Example iex> %Metabase.RequestOperation{} ...> |> Map.put(:body, username: "person@mymetabase.com", password: "fakepassword") ...> |> Map.put(:method, :post) ...> |> Map.put(:path, "/session") ...> |> Metabase.send(host: "mymetabase.com/api") {:ok, %Metabase.Response{}} ## Configuration The `send/2` function takes a keyword list of configuration options as the second argument. These provide the client with additional details needed to make a request and various other options for how the client should process the request and how it should behave. ### Options * `:client` - HTTP client adapter used to make the request. Defaults to `Metabase.HTTP.Hackney`. * `:client_opts` - Configuration options passed to the client adapter * `:headers` - HTTP headers used when making a request * `:host` - Hostname used when making a request. This field is required. * `:json_codec` - Module used to encode and decode JSON. Defaults to `Jason`. * `:port` - HTTP port used when making a request * `:protocol` - HTTP protocol used when making a request * `:retry` - Module implementing a request retry strategy. Disabled when set to `false`. Defaults to `false`. * `:retry_opts` - Options used to control the behavior of the retry module """ alias Metabase.{HTTP, Opts, Request, RequestOperation, Response} @type headers_t :: [{String.t(), String.t()}] @type method_t :: :delete | :get | :head | :patch | :post | :put @type response_t :: {:ok, Response.t()} | {:error, Response.t() | any} @type status_code_t :: pos_integer @doc """ Send an HTTP request. """ @spec send( RequestOperation.t(), keyword ) :: Response.t() def send(operation, old_opts) do opts = Opts.new(old_opts) request = Request.new(operation, opts) case opts.client.send(request, opts) do {:ok, %HTTP.Response{status_code: status_code} = response} when status_code >= 400 -> {:error, Response.new(response, opts)} {:ok, %HTTP.Response{status_code: status_code} = response} when status_code >= 200 -> {:ok, Response.new(response, opts)} otherwise -> otherwise end end end