1defmodule Atex.XRPC do
2 alias Atex.XRPC
3
4 defp adapter do
5 Application.get_env(:atex, :adapter, XRPC.Adapter.Req)
6 end
7
8 # TODO: automatic user-agent, and env for changing it
9
10 # TODO: consistent struct shape/protocol for Lexicon schemas so that user can pass in
11 # an object (hopefully validated by its module) without needing to specify the
12 # name & opts separately, and possibly verify the output response against it?
13
14 # TODO: auto refresh, will need to return a client instance in each method.
15
16 @doc """
17 Perform a HTTP GET on a XRPC resource. Called a "query" in lexicons.
18 """
19 @spec get(XRPC.Client.t(), String.t(), keyword()) :: XRPC.Adapter.result()
20 def get(%XRPC.Client{} = client, name, opts \\ []) do
21 opts = put_auth(opts, client.access_token)
22 adapter().get(url(client, name), opts)
23 end
24
25 @doc """
26 Perform a HTTP POST on a XRPC resource. Called a "prodecure" in lexicons.
27 """
28 @spec post(XRPC.Client.t(), String.t(), keyword()) :: XRPC.Adapter.result()
29 def post(%XRPC.Client{} = client, name, opts \\ []) do
30 # TODO: look through available HTTP clients and see if they have a
31 # consistent way of providing JSON bodies with auto content-type. If not,
32 # create one for adapters.
33 opts = put_auth(opts, client.access_token)
34 adapter().post(url(client, name), opts)
35 end
36
37 @doc """
38 Like `get/3` but is unauthenticated by default.
39 """
40 @spec unauthed_get(String.t(), String.t(), keyword()) :: XRPC.Adapter.result()
41 def unauthed_get(endpoint, name, opts \\ []) do
42 adapter().get(url(endpoint, name), opts)
43 end
44
45 @doc """
46 Like `post/3` but is unauthenticated by default.
47 """
48 @spec unauthed_post(String.t(), String.t(), keyword()) :: XRPC.Adapter.result()
49 def unauthed_post(endpoint, name, opts \\ []) do
50 adapter().post(url(endpoint, name), opts)
51 end
52
53 # TODO: use URI module for joining instead?
54 @spec url(XRPC.Client.t() | String.t(), String.t()) :: String.t()
55 defp url(%XRPC.Client{endpoint: endpoint}, name), do: url(endpoint, name)
56 defp url(endpoint, name) when is_binary(endpoint), do: "#{endpoint}/xrpc/#{name}"
57
58 @doc """
59 Put an `authorization` header into a keyword list of options to pass to a HTTP client.
60 """
61 @spec put_auth(keyword(), String.t()) :: keyword()
62 def put_auth(opts, token),
63 do: put_headers(opts, authorization: "Bearer #{token}")
64
65 @spec put_headers(keyword(), keyword()) :: keyword()
66 defp put_headers(opts, headers) do
67 opts
68 |> Keyword.put_new(:headers, [])
69 |> Keyword.update(:headers, [], &Keyword.merge(&1, headers))
70 end
71end