lib/cloudflare_api.ex

defmodule CloudflareApi do
  @moduledoc """

  _NOTE:  This package is still under active development and may be refactored
  in substantive ways very soon.  If you need to get to prod soon, you may
  want to find an alternative._

  `CloudflareApi` is a thin wrapper around the Cloudflare API.  It provides
  convenient functions and elixir idioms so you don't have to use HTTP directly.

  This library subscribes to the philosophy that you a well-designed REST API
  doesn't need
  a heavy layer of abstraction on top.  There is extensive documentation for
  the CloudFlare API already, and abstracting that away .  The downside of
  course is that if you _want_ to be shielded from the API details, this isn't
  the package for you.

  For example, if you wanted to call
  [the Cloudflare endpoint for listing DNS records](https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records):

  ```
  GET zones/:zone_identifier/dns_records
  ```

  rather than using one of the many HTTP clients, you can do:

  ```
  CloudflareApi.DnsRecords.list(client, zone_id)
  ```

  The extensive query string prameters options that CloudFlare offers are
  also accessible through an `opts` `KeywordList`:

  ```
  CloudflareApi.DnsRecords.list(client, zone_id, name: hostname, type: "A")
  ```

  You may wish to look through the Livebook for an example of usage.

  _NOTE:  This package is still very new and is far from feature complete.  The
  most common endpoints will be created first, but if you need one that isn't
  provided yet you can open an issue on Github (or send a pull request).
  Because this layer is very thin, it doesn't usually take long to add new
  endpoints._

  """

  @doc ~S"""
  Get a preconfigured client you can pass in to other functions

  This makes it so that you don't have to provide the `cloudflare_api_token`
  to every function call.

  ## Examples:

    iex> CloudflareApi.new("<your_token>")

  """
  def new(cloudflare_api_token) do
    Tesla.client([
      {Tesla.Middleware.BaseUrl, "https://api.cloudflare.com/client/v4"},
      Tesla.Middleware.JSON,
      {Tesla.Middleware.BearerAuth, token: cloudflare_api_token}
    ])
  end

  @doc ~S"""
  Returns a function that you can use to easily pass clients in your code.

  This makes it so you don't have to create your own client for every
  function call.  If you are going to make multiple calls then this is
  recommended for convenience and simplicity.  For example:

  ```
  # Get a function that wraps your token for you
  client = CloudflareApi.client("<my_token>")

  # Now you can call other functions like this:
  CloudflareApi.DnsRecords.list(client(), "my_zone_id)

  # If you are going to do additional processing, you can use a pipe:
  client(api_token)
  |> CloudflareApi.list("my_zone_id")
  |> Enum.map(fn record -> {record} end)
  ```

  """
  def client(cloudflare_api_token) do
    c = CloudflareApi.new(cloudflare_api_token)
    fn -> c end
  end

  @doc false
  def uri_encode_opts(opts) do
    URI.encode_query(opts, :rfc3986)
  end
end

# HTTP
# |> auth("Bearer <token>")
# |> headers(accept: "application/json")
# |> headers("content-type":, "application/json")
# |> get("https://example.con/api/v1/hello?name=bob")

# cf = CloudflareApi.client(token)
# ClouflareApi.list_dns_records(cf)
#
#
# CloudflareApi.client(token)
# |> ClouflareApi.DnsRecords.list()
# |> Enum.map(fn a -> a end)