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