defmodule TalkJS do @external_resource "./README.md" @moduledoc """ #{File.read!(@external_resource) |> String.split("---", parts: 2) |> List.last()} """ @typedoc "TalkJS config" @type t :: %__MODULE__{ api_key: binary(), app_id: binary(), base_url: binary(), http_client: term } defstruct [ :api_key, :app_id, base_url: "https://api.talkjs.com/v1/", http_client: TalkJS.HTTPClient.HTTPC ] @doc """ Create a new TalkJS client Options for the TalkJS client:application * `:api_key` - the API key provided by TalkJS (YOUR_SECRET_KEY) * `:app_id` - the app id provided by TalkJS (YOUR_APP_ID) * `:base_url` - the base URL for the API (default: "https://api.talkjs.com/v1/") * `:http_client` - the HTTP client to use (default: TalkJS.HTTPClient.HTTPC). Must adhere to `TalkJS.HTTPClient` behaviour Example usage: ```elixir client = TalkJS.new(api_key: "...", app_id: "...") ``` """ @spec new(opts :: Keyword.t()) :: TalkJS.t() def new(opts) do client = struct!(__MODULE__, opts) client.http_client.init() validate!(opts, :api_key) validate!(opts, :app_id) client end defp validate!(opts, key) do case Keyword.fetch(opts, key) do {:ok, _} -> :ok :error -> raise ArgumentError, "missing required option: #{key}" end end @doc """ Perform a request to TalkJS Example usage: ```elixir client = TalkJS.new(api_key: "...", app_id: "...") TalkJS.request(:get, "$app_id/users/#id", client, %{}) ``` """ @spec request( method :: :get | :delete | :post | :put, path :: String.t(), client :: TalkJS.t(), params :: map(), opts :: Keyword.t() ) :: {:ok, term()} | {:error, term()} def request(method, path, client, params, opts \\ []) def request(method, path, client, _params, opts) when method in [:get, :delete] do url = URI.parse(client.base_url <> path) |> URI.to_string() headers = build_headers(client) do_request(client, method, url, headers, "", opts) end def request(method, path, client, params, opts) when method in [:post, :put] do url = client.base_url <> path headers = build_headers(client) body = (params || %{}) |> Jason.encode!(params) do_request(client, method, url, headers, body, opts) end defp do_request(client, method, url, headers, body, opts) do http_opts = opts[:http_opts] || [] case client.http_client.request(method, url, headers, body, http_opts) do {:ok, %{status: status} = resp} when status >= 200 and status < 300 -> decoded_body = Jason.decode!(resp.body) {:ok, decoded_body} {:ok, resp} -> # IO.inspect(resp) decoded_body = Jason.decode!(resp.body) {:error, decoded_body} {:error, error} -> {:error, error} end end defp build_headers(client) do [ {"authorization", "Bearer #{client.api_key}"} ] end end