GreenFairy.Type (GreenFairy v0.3.0)
View SourceDefines a GraphQL object type with a clean DSL.
Usage
defmodule MyApp.GraphQL.Types.User do
use GreenFairy.Type
type "User", struct: MyApp.User do
@desc "A user in the system"
implements MyApp.GraphQL.Interfaces.Node
field :id, :id, null: false
field :email, :string, null: false
field :name, :string
field :full_name, :string do
resolve fn user, _, _ ->
{:ok, "#{user.first_name} #{user.last_name}"}
end
end
end
endOptions
:struct- The backing Elixir struct for this type (used for resolve_type):description- Description of the type (can also use @desc)
Summary
Functions
Sets up field-level authorization for this type.
Exposes this type as a query field, fetchable by the given field.
Defines a GraphQL object type.
Controls whether this type or field appears in introspection results.
Functions
Sets up field-level authorization for this type.
Function-based Authorization (Recommended)
Pass a function that receives the object and context, returns visible fields:
type "User", struct: MyApp.User do
authorize fn user, ctx ->
cond do
ctx[:current_user]?.admin -> :all
ctx[:current_user]?.id == user.id -> :all
true -> [:id, :name]
end
end
field :id, non_null(:id)
field :name, :string
field :email, :string
field :ssn, :string
endWith Path/Parent Info
Use 3-arity function to access path through the graph:
type "Comment", struct: MyApp.Comment do
authorize fn comment, ctx, info ->
# info.path = [:query, :user, :posts, :comments]
# info.parent = %Post{...}
# info.parents = [%User{}, %Post{}]
post = info.parent
if post.public, do: :all, else: [:id, :body]
end
field :id, non_null(:id)
field :body, :string
field :author, :user
endReturn Values
:all- All fields visible:none- Object filtered from results (no access)[:field1, :field2]- Only these fields visible
Legacy Policy-based Authorization
For backwards compatibility, you can still use a policy module:
type "User", struct: MyApp.User do
authorize with: MyApp.Policies.User
# ...
end
Exposes this type as a query field, fetchable by the given field.
The field type is automatically inferred from the struct's adapter.
Usage
type "User", struct: MyApp.User do
expose :id # Generates query: user(id: ID!): User
expose :email # Generates query: userByEmail(email: String!): User
field :id, non_null(:id)
field :email, :string
field :name, :string
endOptions
:as- Custom query field name (default: type_name or type_name_by_field):unique- Whether this field is unique (default: true for :id, false otherwise)
Generated Queries
For expose :id:
- Query field name:
:user(singular of type name) - Fetches via:
Repo.get(User, id)
For expose :email:
- Query field name:
:user_by_email - Fetches via:
Repo.get_by(User, email: email)
How It Works
- The field type is looked up from the adapter (Ecto schema, etc.)
- A query field is auto-generated with the appropriate arg type
- The resolver decodes GlobalId (if :id) or uses the raw value
- Fetches from the database using the schema's configured repo
Defines a GraphQL object type.
Examples
type "User" do
field :id, :id
field :name, :string
end
type "User", struct: MyApp.User do
field :id, :id
end
Controls whether this type or field appears in introspection results.
Unlike authorize, which controls data access at resolution time (and requires
an object), visible controls schema visibility based only on context.
Type-level visibility
type "InternalMetrics", struct: MyApp.InternalMetrics do
visible fn ctx -> ctx[:current_user][:admin] end
field :cpu, :float
field :memory, :float
endField-level visibility
type "User", struct: MyApp.User do
field :id, non_null(:id)
field :name, :string
field :ssn, :string do
visible fn ctx -> ctx[:current_user][:admin] end
end
end