defmodule ExSynapse do @moduledoc false alias ExSynapse.{ApiConnectionError, ApiError, AuthenticationError, IncorrectValuesError, InvalidRequestError, RateLimitError, RequestFailedError} @base_url "https://uat-api.synapsefi.com/v3.1" @missing_auth_info_message "The client_id and client_secret settings are required to use Synapse." def request(action, endpoint, data, opts) when action in [:get, :post, :delete, :patch] do action |> HTTPoison.request(Path.join(get_api_endpoint(), endpoint), Poison.encode!(data), create_headers(opts)) |> handle_response() end defp get_client_id do from_env(:ex_synapse, :client_id) || raise(AuthenticationError, message: @missing_auth_info_message) end defp get_client_secret do from_env(:ex_synapse, :client_secret) || raise(AuthenticationError, message: @missing_auth_info_message) end defp get_api_endpoint do from_env(:ex_synapse, :api_endpoint) || @base_url end defp create_headers(opts) do [ {"X-SP-GATEWAY", "#{get_client_id()}|#{get_client_secret()}"}, {"X-SP-LANG", "en"}, {"Content-Type", "application/json"}, {"Accept", "application/json"}, ] |> MapSet.new() |> assign_user_ip(opts) |> assign_user(opts) |> assign_idempotency_key(opts) end defp assign_user_ip(headers, opts) do case Keyword.get(opts, :user_ip) do nil -> headers user_ip -> MapSet.put headers, {"X-SP-USER-IP", user_ip} end end defp assign_user(headers, opts) do user_oauth_key = Keyword.get(opts, :user_oauth_key) user_fingerprint = Keyword.get(opts, :user_fingerprint) if user_oauth_key == nil and user_fingerprint == nil do headers else user_header = create_user_header(user_oauth_key, user_fingerprint) MapSet.put headers, user_header end end defp assign_idempotency_key(headers, opts) do case Keyword.get(opts, :idempotency_key) do nil -> headers idempotency_key -> MapSet.put headers, {"X-SP-IDEMPOTENCY-KEY", idempotency_key} end end defp create_user_header(user_oauth_key, user_fingerprint) defp create_user_header(nil, user_fingerprint) do {"X-SP-USER", "|#{user_fingerprint}"} end defp create_user_header(user_oauth_key, user_fingerprint) do {"X-SP-USER", "#{user_oauth_key}|#{user_fingerprint}"} end defp handle_response({:ok, %{body: body, status_code: 200}}) do {:ok, process_response_body(body)} end defp handle_response({:ok, %{body: body, status_code: status_code}}) do message = body |> process_response_body() |> Map.fetch!("error") |> Map.fetch!("en") error_struct = case status_code do status_code when status_code in [400, 404] -> %InvalidRequestError{message: message} 401 -> %AuthenticationError{message: message} 402 -> %RequestFailedError{message: message} 409 -> %IncorrectValuesError{message: message} 429 -> %RateLimitError{message: message} _ -> %ApiError{message: message} end {:error, error_struct} end defp handle_response({:error, %HTTPoison.Error{reason: reason}}) do %ApiConnectionError{message: "Network Error: #{reason}"} end defp process_response_body(body) do Poison.decode! body end defp from_env(otp_app, key, default \\ nil) defp from_env(otp_app, key, default) do otp_app |> Application.get_env(key, default) |> read_env_from_system(default) end defp read_env_from_system({:system, env}, default) do System.get_env(env) || default end defp read_env_from_system(value, _default) do value end end