Current section
Files
Jump to
Current section
Files
lib/ex_paymob/client.ex
defmodule ExPaymob.Client do
@moduledoc """
HTTP client that builds requests and delegates to the configured HTTP adapter.
"""
alias ExPaymob.{Config, Error, Response}
@doc """
Executes an API request.
"""
@spec request(atom(), String.t(), map(), keyword()) ::
{:ok, map() | list()} | {:error, Error.t()}
def request(method, endpoint, params \\ %{}, opts \\ []) do
base_url = Config.resolve_base_url(opts)
secret_key = Config.resolve(:secret_key, opts)
http_client = Config.resolve_http_client(opts)
json_library = Config.resolve_json_library(opts)
url = build_url(base_url, endpoint)
headers = build_headers(secret_key)
body =
case method do
:get -> nil
_ -> json_library.encode!(params)
end
case http_client.request(method, url, headers, body, opts) do
{:ok, status, _resp_headers, resp_body} ->
handle_response(status, resp_body, opts)
{:error, reason} ->
{:error, Error.network_error(reason)}
end
end
defp build_url(base_url, endpoint) do
base_url
|> String.trim_trailing("/")
|> Kernel.<>(endpoint)
end
defp build_headers(nil) do
[{"content-type", "application/json"}]
end
defp build_headers(secret_key) do
[
{"authorization", "Token #{secret_key}"},
{"content-type", "application/json"}
]
end
defp handle_response(status, resp_body, opts) when status in 200..299 do
case Response.decode(resp_body, opts) do
{:ok, body} -> {:ok, body}
{:error, _} -> {:error, Error.internal_error("Failed to decode response body")}
end
end
defp handle_response(status, resp_body, opts) do
case Response.decode(resp_body, opts) do
{:ok, body} -> {:error, Error.api_error(status, body)}
{:error, _} -> {:error, Error.api_error(status, resp_body)}
end
end
end