Gateway
=======
A set of macros and conventions to build clients that communicate with REST apis
>Note: this is poorly tested (but still tested!) beta software, use at your own peril
HowTo: An Example
=================
We've been tasked with building a client library for Stripe's API.
We can do that easily using Gateway's macros like so:
In `lib/stripe.ex`, we use Gateway with a list of header and corresponding values.
Gateway automatically puts these things into `process_request_headers/1` method used by `HTTPoison.Base`
```elixir
defmodule Stripe do
use Gateway, [{:Authorization, :secret_key}]
end
```
In `lib/stripe/account.ex`, we define what the remote resource would look like.
For the use case of Stripe's Account objects, the information can be found on Stripe's site: https://stripe.com/docs/api/curl#account_object
For clarity, we will only 4 fields. In future real gateway clients, we may want to include all the fields the foreign API service provides.
```elixir
defmodule Stripe.Account do
defstruct [:id, :email, :display_name]
end
```
In `lib/stripe/accounts.ex`, we denote the `@endpoint` url and the `@resource`. If no `@resource` is specified, Gateway will automatically assume it's the singularized version of its current module.
Most companies expect the `update` method to be called with `put`, but in the case of Stripe, it is done with `post`. We specify that in the `use/2` macro.
Finally, we override Gateway's default `all_type/0`, on `all` requests to accounts, Stripe's response embeds the account data under the "data" field. We need to let gateway know how to handle this by redefining `all_type/0`
```elixir
defmodule Stripe.Accounts do
@endpoint "/api/accounts/:id"
@resource Stripe.Account
use Gateway.Resource, update: :post
def all_type, do: %{"data" => [@resource]}
end
```
Finally, `config/config.exs`, we define Stripe's host url, and our secret key.
```elixir
config :gateway, Stripe,
url: "http://api.stripe.com",
secret_key: "Bearer pk_my_secret_key"
```
And we are done (with Stripe's account API)! Use it like so:
```elixir
{:ok, account} = Stripe.Account.get "acc_231as"
# Retrives account id "acc_231as"
{:ok, accounts} = Stripe.Accounts.all
# Retrieves all accounts
{:ok, accounts} = Stripe.Accounts.all %{"some_search_param" => "some_value"}
# Retrives accounts according to your query (see Stripe's site for more details)
{:ok, account} = Stripe.Accounts.create %{"email" => "test@example.com", "other_fields" => "other_values"}
# Creates an account remotely on Stripe
{:ok, account} = account.id |> Stripe.Accounts.update(%{"email" => "another-email@example.com"})
# Updates an existing account on Stripe
{:ok, account} = account.id |> Stripe.Accounts.delete
# Deletes this account from Stripe
```