defmodule Plaid do @moduledoc """ An HTTP Client for Plaid. [Plaid API Docs](https://plaid.com/docs/api) """ use HTTPoison.Base defmodule MissingClientIdError do defexception message: """ The `client_id` is required for calls to Plaid. Please either configure `client_id` in your config.exs file or pass it into the function via the `config` argument. config :plaid, client_id: "your_client_id" """ end defmodule MissingSecretError do defexception message: """ The `secret` is required for calls to Plaid. Please either configure `secret` in your config.exs file or pass it into the function via the `config` argument. config :plaid, secret: "your_secret" """ end defmodule MissingPublicKeyError do defexception message: """ The `public_key` is required for some unauthenticated endpoints. Please either configure `public_key` in your config.exs or pass it into the function via the `config` argument. config :plaid, public_key: "your_public_key" """ end defmodule MissingRootUriError do defexception message: """ The root_uri is required to specify the Plaid environment to which you are making calls, i.e. sandbox, development or production. Please configure root_uri in your config.exs file. config :plaid, root_uri: "https://sandbox.plaid.com/" (test) config :plaid, root_uri: "https://development.plaid.com/" (development) config :plaid, root_uri: "https://production.plaid.com/" (production) """ end @doc """ Gets credentials from configuration. """ @spec get_cred() :: map | no_return @deprecated "Use `Plaid.validate_cred/1` which accepts a runtime config argument." def get_cred do %{ client_id: get_client_id(%{}), secret: get_secret(%{}) } end @doc """ Gets public_key from configuration. """ @spec get_key() :: map | no_return @deprecated "Use `Plaid.validate_public_key/1` which accepts a runtime config argument." def get_key do %{ public_key: get_public_key(%{}) } end @doc """ Makes request without credentials. """ @spec make_request(atom, String.t(), map, map, Keyword.t()) :: {:ok, HTTPoison.Response.t()} | {:error, HTTPoison.Error.t()} @deprecated "Use `Plaid.make_request_with_cred/3`. This function doesn't allow runtime configuration of the root_uri." def make_request(method, endpoint, body \\ %{}, headers \\ %{}, options \\ []) do make_request_with_cred(method, endpoint, %{}, body, headers, options) end @doc """ Makes request with credentials. """ @spec make_request_with_cred(atom, String.t(), map, map, map, Keyword.t()) :: {:ok, HTTPoison.Response.t()} | {:error, HTTPoison.Error.t()} def make_request_with_cred(method, endpoint, config, body \\ %{}, headers \\ %{}, options \\ []) do request_endpoint = "#{get_root_uri(config)}#{endpoint}" cred = Map.delete(config, :root_uri) request_body = Map.merge(body, cred) |> Poison.encode!() request_headers = get_request_headers() |> Map.merge(headers) |> Map.to_list() options = httpoison_request_options() ++ options request(method, request_endpoint, request_body, request_headers, options) end def process_response_body(body) do Poison.Parser.parse!(body, %{}) end defp get_request_headers do Map.new() |> Map.put("Content-Type", "application/json") end defp httpoison_request_options do Application.get_env(:plaid, :httpoison_options, []) end @doc """ Gets the `client_id` and `secret` from config argument or the library configuration. """ @spec validate_cred(map) :: map | no_return def validate_cred(config) do %{ client_id: get_client_id(config), secret: get_secret(config), root_uri: get_root_uri(config) } end @doc """ Gets the `public_key` from the config argument or library configuration. """ @deprecated "Plaid no longer uses public keys for new accounts." @spec validate_public_key(map) :: map | no_return def validate_public_key(config) do %{ public_key: get_public_key(config), root_uri: get_root_uri(config) } end defp get_client_id(config) do case Map.get(config, :client_id) || Application.get_env(:plaid, :client_id) do nil -> raise MissingClientIdError client_id -> client_id end end defp get_secret(config) do case Map.get(config, :secret) || Application.get_env(:plaid, :secret) do nil -> raise MissingSecretError secret -> secret end end defp get_public_key(config) do case Map.get(config, :public_key) || Application.get_env(:plaid, :public_key) do nil -> raise MissingPublicKeyError public_key -> public_key end end defp get_root_uri(config) do case Map.get(config, :root_uri) || Application.get_env(:plaid, :root_uri) do nil -> raise MissingRootUriError root_uri -> root_uri end end end