Current section
Files
Jump to
Current section
Files
lib/resend/client.ex
defmodule Resend.Client do
@moduledoc """
Resend API client.
"""
require Logger
alias Resend.Castable
@callback post(t(), String.t(), map()) ::
{:ok, %{body: map(), status: pos_integer()}} | {:error, any()}
@type response(type) :: {:ok, type} | {:error, Resend.Error.t() | :client_error}
@type t() :: %__MODULE__{
api_key: String.t(),
base_url: String.t() | nil,
client: module() | nil
}
@enforce_keys [:api_key, :base_url, :client]
defstruct [:api_key, :base_url, :client]
@default_opts [
base_url: "https://api.resend.com",
client: __MODULE__.TeslaClient
]
@doc """
Creates a new Resend client struct given a keyword list of config opts.
"""
@spec new(Resend.config()) :: t()
def new(config) do
config = Keyword.take(config, [:api_key, :base_url, :client])
struct!(__MODULE__, Keyword.merge(@default_opts, config))
end
@spec post(t(), String.t(), atom(), map()) :: response(any())
def post(client, path, castable_module, body) do
client_module = client.client || Resend.Client.TeslaClient
case client_module.post(client, path, body) do
{:ok, %{body: body, status: status}} when status in 200..299 ->
{:ok, Castable.cast(castable_module, body)}
{:ok, %{body: body}} when is_map(body) ->
Logger.error("#{inspect(__MODULE__)} error when calling #{path}: #{inspect(body)}")
{:error, Castable.cast(Resend.Error, body)}
{:ok, %{body: body}} when is_binary(body) ->
Logger.error("#{inspect(__MODULE__)} error when calling #{path}: #{body}")
{:error, body}
{:error, reason} ->
Logger.error("#{inspect(__MODULE__)} error when calling #{path}: #{inspect(reason)}")
{:error, :client_error}
end
end
end