Current section

Files

Jump to
campaign_flow lib campaign_flow client.ex
Raw

lib/campaign_flow/client.ex

defmodule CampaignFlow.Client do
@moduledoc """
Main client module for the Campaign Flow API.
This module provides a convenient interface for interacting with the Campaign Flow API
using OAuth2 authentication and the Req HTTP client library.
## Configuration
You can configure the client in your config files:
config :campaign_flow,
base_url: "https://app.campaignflow.com.au/api/v2",
client_id: "your_client_id",
client_secret: "your_client_secret"
Or pass configuration directly when creating a client:
client = CampaignFlow.Client.new(
base_url: "https://app.campaignflow.com.au/api/v2",
client_id: "your_client_id",
client_secret: "your_client_secret"
)
## Usage
# Create a new client
client = CampaignFlow.Client.new(
client_id: "your_client_id",
client_secret: "your_client_secret"
)
# Make API calls using resource modules
{:ok, campaigns} = CampaignFlow.Client.Campaigns.list(client)
{:ok, campaign} = CampaignFlow.Client.Campaigns.get(client, campaign_id)
"""
alias CampaignFlow.Client.Auth
@type t :: %__MODULE__{
base_url: String.t(),
client_id: String.t(),
client_secret: String.t(),
access_token: String.t() | nil,
token_expires_at: DateTime.t() | nil,
req_options: keyword()
}
defstruct [
:base_url,
:client_id,
:client_secret,
:access_token,
:token_expires_at,
req_options: []
]
# Private functions
defp default_base_url(opts, config) do
environment = opts[:environment] || config[:environment] || :prod
case environment do
env when env in [:test, "test"] -> "https://test.campaignflow.com.au/api/v2"
env when env in [:prod, "prod"] -> "https://app.campaignflow.com.au/api/v2"
_ -> raise "Invalid environment: #{inspect(environment)}. Must be :prod or :test"
end
end
# Public API
@doc """
Creates a new Campaign Flow API client.
## Options
* `:base_url` - The base URL for the API (overrides environment setting)
* `:environment` - The environment to use (`:prod` or `:test`, defaults to `:prod`)
* `:client_id` - OAuth2 client ID (required)
* `:client_secret` - OAuth2 client secret (required)
* `:req_options` - Additional options to pass to Req
## Examples
client = CampaignFlow.Client.new(client_id: "id", client_secret: "secret")
#=> %CampaignFlow.Client{...}
client = CampaignFlow.Client.new(client_id: "id", client_secret: "secret", environment: :test)
#=> %CampaignFlow.Client{base_url: "https://test.campaignflow.com.au/api/v2", ...}
"""
@spec new(keyword()) :: t()
def new(opts \\ []) do
config = Application.get_all_env(:campaign_flow)
%__MODULE__{
base_url: opts[:base_url] || config[:base_url] || default_base_url(opts, config),
client_id: opts[:client_id] || config[:client_id] || raise("client_id is required"),
client_secret:
opts[:client_secret] || config[:client_secret] || raise("client_secret is required"),
req_options: opts[:req_options] || []
}
end
@doc """
Creates a new client for the test environment.
## Examples
client = CampaignFlow.Client.test(client_id: "id", client_secret: "secret")
#=> %CampaignFlow.Client{base_url: "https://test.campaignflow.com.au/api/v2", ...}
"""
@spec test(keyword()) :: t()
def test(opts \\ []) do
opts
|> Keyword.put(:base_url, "https://test.campaignflow.com.au/api/v2")
|> new()
end
@doc """
Ensures the client has a valid access token, refreshing if necessary.
## Examples
client = CampaignFlow.Client.new(client_id: "id", client_secret: "secret")
{:ok, authenticated_client} = CampaignFlow.Client.authenticate(client)
"""
@spec authenticate(t()) :: {:ok, t()} | {:error, term()}
def authenticate(%__MODULE__{} = client) do
if token_valid?(client) do
{:ok, client}
else
Auth.get_access_token(client)
end
end
@doc """
Checks if the client's current access token is valid.
"""
@spec token_valid?(t()) :: boolean()
def token_valid?(%__MODULE__{access_token: nil}), do: false
def token_valid?(%__MODULE__{token_expires_at: nil}), do: false
def token_valid?(%__MODULE__{token_expires_at: expires_at}) do
DateTime.compare(DateTime.utc_now(), expires_at) == :lt
end
end