lib/gumroad/client.ex

defmodule Gumroad.Client do
  @moduledoc """
  Defines a behaviour of a client that can be used for performing actions against
  a Gumroad implementation.

  Two implementations are provided:

  - `Gumroad.Client.Live` - Default client used in production. This one connects to
      the Gumroad API.
  - `Gumroad.Client.Mock` - Client to be used in tests. This returns canned responses
      _without_ making requests to the Gurmoad API.

  You can configure your application to use either of these implementation by setting
  the `:gumroad_elixir`, `:client` config property:

  ```elixir
  # In test mode, you'd probably want to use the Mock implementation
  # config/test.exs
  config :gumroad_elixir, :client, Gumroad.Client.Mock

  # In prod, you should use the Live implementation (which is the default)
  # config/prod.exs
  config :gumroad_elixir, :client, Gumroad.Client.Live
  ```
  """

  @doc """
  Retrieve all of the existing products.

  ## API

  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `GET /products`.
  """
  @callback get_products() :: {:ok, list(Gumroad.Product.t())} | {:error, Gumroad.Error.t()}

  @doc """
  Retrieve the details of a product.

  ## API

  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `GET /products/:id`.
  """
  @callback get_product(product_id :: String.t()) ::
              {:ok, Gumroad.Product.t()} | {:error, Gumroad.Error.t()}

  @doc """
  Retrieve all active subscriptions for the given resource name.

  Valid resource names are:
  - `sale`
  - `refund`
  - `dispute`
  - `dispute_won`
  - `cancellation`
  - `subscription_updated`
  - `subscription_ended`
  - `subscription_restarted`

  ## API
  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `GET /resource_subscriptions`.
  """
  @callback get_resource_subscriptions(resource_name :: String.t()) ::
              {:ok, list(Gumroad.ResourceSubscription.t())} | {:error, Gumroad.Error.t()}

  @doc """
  Subscribe to a resource.

  Valid resource names are:

  - `sale`
  - `refund`
  - `dispute`
  - `dispute_won`
  - `cancellation`
  - `subscription_updated`
  - `subscription_ended`
  - `subscription_restarted`

  ## API
  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `PUT /resource_subscriptions`.
  """
  @callback create_resource_subscription(params :: Gumroad.ResourceSubscription.create_params()) ::
              {:ok, Gumroad.ResourceSubscription.t()} | {:error, Gumroad.Error.t()}

  @doc """
  Unsubscribe from a resource.

  ## API
  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `DELETE /resource_subscriptions/:resource_subscription_id`.
  """
  @callback delete_resource_subscription(resource_subscription_id :: String.t()) ::
              {:ok} | {:error, Gumroad.Error.t()}

  @doc """
  Retrieve the subscribers of the given product.

  ## API
  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `GET /products/:product_id/subcribers`.
  """
  @callback get_subscribers(product_id :: String.t()) ::
              {:ok, list(Gumroad.Subscriber.t())} | {:error, Gumroad.Error.t()}

  @doc """
  Retrieve a subscriber by their ID.

  ## API
  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `GET /subscribers/:id`.
  """
  @callback get_subscriber(subscriber_id :: String.t()) ::
              {:ok, Gumroad.Subscriber.t()} | {:error, Gumroad.Error.t()}

  @doc """
  Retrieve a sale by its ID.

  ## API
  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `GET /sales/:id`.
  """
  @callback get_sale(sale_id :: String.t()) ::
              {:ok, Gumroad.Sale.t()} | {:error, Gumroad.Error.t()}

  @type get_sales_params :: %{
          after: String.t() | nil,
          before: String.t() | nil,
          product_id: String.t() | nil,
          email: String.t() | nil,
          order_id: String.t() | nil,
          page: number()
        }

  @doc """
  Retrieves all of the successful sales by the authenticated user.

  ## Parameters
  * `after` (optional, date in form YYYY-MM-DD) - Only return sales after this date
  * `before` (optional, date in form YYYY-MM-DD) - Only return sales before this date
  * `product_id` (optional) - Filter sales by this product
  * `email` (optional) - Filter sales by this email
  * `order_id` (optional) - Filter sales by this Order ID
  * `page` (number) - Return this page of results

  ## API
  When using `Gumroad.Client.Live`, this will call the Gumroad API at
  `GET /sales`.
  """
  @callback get_sales(params :: get_sales_params()) ::
              {:ok, list(Gumroad.Sale.t())} | {:error, Gumroad.Error.t()}
end