Current section

Files

Jump to
sanity lib sanity.ex
Raw

lib/sanity.ex

defmodule Sanity do
alias Sanity.{Request, Response}
# FIXME review for consistency with Javascript client-lib
def mutate(mutations, query_params \\ []) when is_list(mutations) do
%Request{
body: Jason.encode!(%{mutations: mutations}),
endpoint: :mutate,
method: :post,
query_params: camelize_params(query_params)
}
end
def query(query, variables \\ %{}, query_params \\ []) do
query_params =
variables
|> stringify_keys()
|> Enum.map(fn {k, v} -> {"$#{k}", Jason.encode!(v)} end)
|> Enum.into(camelize_params(query_params))
|> Map.put("query", query)
%Request{
endpoint: :query,
method: :get,
query_params: query_params
}
end
def request(
%Request{body: body, method: method, query_params: query_params} = request,
opts \\ []
) do
# TODO support client opts, like :receive_timeout
url = "#{url_for(request, opts)}?#{URI.encode_query(query_params)}"
Finch.build(method, url, headers(opts), body)
|> Finch.request(Sanity.Finch)
|> case do
{:ok, %Finch.Response{body: body, headers: headers, status: status}}
when status in 200..299 ->
{:ok, %Response{body: Jason.decode!(body), headers: headers}}
{:ok, %Finch.Response{body: body, headers: headers, status: status}}
when status in 400..499 ->
{:error, %Response{body: Jason.decode!(body), headers: headers}}
end
# TODO raise a more useful exception than MatchError on http error
end
defp base_url(opts) do
# FIXME support cdn
project_id = Keyword.fetch!(opts, :project_id)
"https://#{project_id}.api.sanity.io"
end
defp headers(opts) do
case Keyword.fetch(opts, :token) do
{:ok, token} -> [{"authorization", "Bearer #{token}"}]
:error -> []
end
end
defp camelize_params(pairs) do
pairs
|> stringify_keys()
|> Enum.map(fn {k, v} ->
{first, rest} = k |> Macro.camelize() |> String.split_at(1)
{String.downcase(first) <> rest, v}
end)
|> Map.new()
end
defp stringify_keys(pairs) do
pairs
|> Enum.map(fn
{k, v} when is_binary(k) -> {k, v}
{k, v} when is_atom(k) -> {Atom.to_string(k), v}
end)
|> Map.new()
end
defp url_for(%Request{endpoint: :mutate}, opts) do
"#{base_url(opts)}/v1/data/mutate/#{Keyword.fetch!(opts, :dataset)}"
end
defp url_for(%Request{endpoint: :query}, opts) do
"#{base_url(opts)}/v1/data/query/#{Keyword.fetch!(opts, :dataset)}"
end
end