Current section
Files
Jump to
Current section
Files
lib/speakeasy.ex
defmodule Speakeasy do
@moduledoc """
Authorize Absinthe queries and mutations.
Please see the [README](readme.html).
"""
@doc """
If authorized returns an anonymous function that encapsulates your GraphQL resolution function.
Otherwise returns the Bodyguard error response.
See [this](readme.html#speakeasy-resolve-2-or-speakeasy-resolve-2) section of the README for usage examples.
## Examples
iex> Speakeasy.resolve(MyApp.Posts, :create_post)
iex> Speakeasy.resolve(MyApp.Posts, :create_post, user_key: :current_user)
"""
@spec resolve(module(), atom(), keyword(atom())) :: function() | :error | {:error, String.t}
def resolve(mod, fun, opts \\ []) do
fn _parent, args, res ->
gql_context = res.context || %{}
case Bodyguard.permit(mod, fun, gql_context, args) do
:ok ->
ctx = context_or_user(gql_context, opts)
send(mod, fun, ctx, args)
:error -> {:error, "Unauthorized"}
{:error, reason} -> {:error, reason}
end
end
end
defp context_or_user(gql_context, :user), do: context_or_user(gql_context, [user_key: :current_user])
defp context_or_user(gql_context, []), do: gql_context
defp context_or_user(gql_context, [user_key: user_key]) do
Map.get(gql_context, user_key) || nil
end
defp send(mod, fun, context, args) do
cond do
:erlang.function_exported(mod, fun, 2) ->
apply(mod, fun, [args, context])
:erlang.function_exported(mod, fun, 1) ->
apply(mod, fun, [args])
:erlang.function_exported(mod, fun, 0) ->
apply(mod, fun, [])
true ->
raise Speakeasy.UnsupportedArityError,
message: Speakeasy.UnsupportedArityError.msg(mod, fun)
end
end
@doc """
Macro form of `resolve/2`. This will cause your application to fail to compile if your
resolution function isn't compatible with what Speakeasy
This function works the same as `resolve/2`
"""
defmacro resolve!(mod, fun, opts \\ []) do
quote do
max_arity =
:functions
|> unquote(mod).__info__
|> Keyword.get_values(unquote(fun))
|> Enum.sort()
|> List.last()
cond do
max_arity > 2 ->
raise Speakeasy.UnsupportedArityError,
message: Speakeasy.UnsupportedArityError.msg(unquote(mod), unquote(fun))
max_arity == nil ->
raise Speakeasy.UnsupportedArityError,
message: Speakeasy.UnsupportedArityError.msg(unquote(mod), unquote(fun))
true ->
Speakeasy.resolve(unquote(mod), unquote(fun), unquote(opts))
end
end
end
end