Packages
absinthe
1.5.0-beta.2
1.11.0
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.8
1.6.7
retired
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.5.0-beta.2
1.5.0-beta.1
1.5.0-beta.0
1.5.0-alpha.4
1.5.0-alpha.3
1.5.0-alpha.2
1.5.0-alpha.1
1.5.0-alpha.0
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
retired
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.4.0-beta.5
1.4.0-beta.4
1.4.0-beta.3
1.4.0-beta.2
1.4.0-beta.1
1.3.2
1.3.1
1.3.0
1.3.0-rc.0
1.3.0-beta.2
1.3.0-beta.1
1.3.0-beta.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.2.0-beta.0
1.2.0-alpha0
1.2.0-alpha.2
1.2.0-alpha.1
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.2.3
0.2.2
0.2.1
0.1.0
GraphQL for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/absinthe/type/interface.ex
defmodule Absinthe.Type.Interface do
@moduledoc """
A defined interface type that represent a list of named fields and their
arguments.
Fields on an interface have the same rules as fields on an
`Absinthe.Type.Object`.
If an `Absinthe.Type.Object` lists an interface in its `:interfaces` entry,
it guarantees that it defines the same fields and arguments that the
interface does.
Because sometimes it's for the interface to determine the implementing type of
a resolved object, you must either:
* Provide a `:resolve_type` function on the interface
* Provide a `:is_type_of` function on each implementing type
```
interface :named_entity do
field :name, :string
resolve_type fn
%{age: _}, _ -> :person
%{employee_count: _}, _ -> :business
_, _ -> nil
end
end
object :person do
field :name, :string
field :age, :string
interface :named_entity
end
object :business do
field :name, :string
field :employee_count, :integer
interface :named_entity
end
```
"""
use Absinthe.Introspection.Kind
alias Absinthe.Type
alias Absinthe.Schema
@typedoc """
* `:name` - The name of the interface type. Should be a TitleCased `binary`. Set automatically.
* `:description` - A nice description for introspection.
* `:fields` - A map of `Absinthe.Type.Field` structs. See `Absinthe.Schema.Notation.field/4` and
* `:args` - A map of `Absinthe.Type.Argument` structs. See `Absinthe.Schema.Notation.arg/2`.
* `:resolve_type` - A function used to determine the implementing type of a resolved object. See also `Absinthe.Type.Object`'s `:is_type_of`.
The `:resolve_type` function will be passed two arguments; the object whose type needs to be identified, and the `Absinthe.Execution` struct providing the full execution context.
The `__private__` and `:__reference__` keys are for internal use.
"""
@type t :: %__MODULE__{
name: binary,
description: binary,
fields: map,
identifier: atom,
__private__: Keyword.t(),
definition: module,
__reference__: Type.Reference.t()
}
defstruct name: nil,
description: nil,
fields: nil,
identifier: nil,
resolve_type: nil,
__private__: [],
definition: nil,
__reference__: nil,
resolve_type: nil
@doc false
defdelegate functions, to: Absinthe.Blueprint.Schema.InterfaceTypeDefinition
@spec resolve_type(Type.Interface.t(), any, Absinthe.Resolution.t()) :: Type.t() | nil
def resolve_type(type, obj, env, opts \\ [lookup: true])
def resolve_type(interface, obj, %{schema: schema} = env, opts) do
implementors = Schema.implementors(schema, interface.identifier)
if resolver = Type.function(interface, :resolve_type) do
case resolver.(obj, env) do
nil ->
nil
ident when is_atom(ident) ->
if opts[:lookup] do
Absinthe.Schema.lookup_type(schema, ident)
else
ident
end
end
else
type_name =
Enum.find(implementors, fn type ->
Absinthe.Type.function(type, :is_type_of).(obj)
end)
if opts[:lookup] do
Absinthe.Schema.lookup_type(schema, type_name)
else
type_name
end
end
end
@doc """
Whether the interface (or implementors) are correctly configured to resolve
objects.
"""
@spec type_resolvable?(Schema.t(), t) :: boolean
def type_resolvable?(schema, %{resolve_type: nil} = iface) do
Schema.implementors(schema, iface)
|> Enum.all?(& &1.is_type_of)
end
def type_resolvable?(_, %{resolve_type: _}) do
true
end
@doc false
@spec member?(t, Type.t()) :: boolean
def member?(%{identifier: ident}, %{interfaces: ifaces}) do
ident in ifaces
end
def member?(_, _) do
false
end
end