Current section

Files

Jump to
atex lib xrpc.ex
Raw

lib/xrpc.ex

defmodule Atex.XRPC do
alias Atex.XRPC
defp adapter do
Application.get_env(:atex, :adapter, XRPC.Adapter.Req)
end
# TODO: automatic user-agent, and env for changing it
# TODO: consistent struct shape/protocol for Lexicon schemas so that user can pass in
# an object (hopefully validated by its module) without needing to specify the
# name & opts separately, and possibly verify the output response against it?
# TODO: auto refresh, will need to return a client instance in each method.
@doc """
Perform a HTTP GET on a XRPC resource. Called a "query" in lexicons.
"""
@spec get(XRPC.Client.t(), String.t(), keyword()) :: XRPC.Adapter.result()
def get(%XRPC.Client{} = client, name, opts \\ []) do
opts = put_auth(opts, client.access_token)
adapter().get(url(client, name), opts)
end
@doc """
Perform a HTTP POST on a XRPC resource. Called a "prodecure" in lexicons.
"""
@spec post(XRPC.Client.t(), String.t(), keyword()) :: XRPC.Adapter.result()
def post(%XRPC.Client{} = client, name, opts \\ []) do
# TODO: look through available HTTP clients and see if they have a
# consistent way of providing JSON bodies with auto content-type. If not,
# create one for adapters.
opts = put_auth(opts, client.access_token)
adapter().post(url(client, name), opts)
end
@doc """
Like `get/3` but is unauthenticated by default.
"""
@spec unauthed_get(String.t(), String.t(), keyword()) :: XRPC.Adapter.result()
def unauthed_get(endpoint, name, opts \\ []) do
adapter().get(url(endpoint, name), opts)
end
@doc """
Like `post/3` but is unauthenticated by default.
"""
@spec unauthed_post(String.t(), String.t(), keyword()) :: XRPC.Adapter.result()
def unauthed_post(endpoint, name, opts \\ []) do
adapter().post(url(endpoint, name), opts)
end
# TODO: use URI module for joining instead?
@spec url(XRPC.Client.t() | String.t(), String.t()) :: String.t()
defp url(%XRPC.Client{endpoint: endpoint}, name), do: url(endpoint, name)
defp url(endpoint, name) when is_binary(endpoint), do: "#{endpoint}/xrpc/#{name}"
@doc """
Put an `authorization` header into a keyword list of options to pass to a HTTP client.
"""
@spec put_auth(keyword(), String.t()) :: keyword()
def put_auth(opts, token),
do: put_headers(opts, authorization: "Bearer #{token}")
@spec put_headers(keyword(), keyword()) :: keyword()
defp put_headers(opts, headers) do
opts
|> Keyword.put_new(:headers, [])
|> Keyword.update(:headers, [], &Keyword.merge(&1, headers))
end
end