GreenFairy.Type (GreenFairy v0.3.0)

View Source

Defines 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
end

Options

  • :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

authorize(func)

(macro)

Sets up field-level authorization for this type.

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
end

With 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
end

Return 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

expose(field_name, opts \\ [])

(macro)

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
end

Options

  • :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

  1. The field type is looked up from the adapter (Ecto schema, etc.)
  2. A query field is auto-generated with the appropriate arg type
  3. The resolver decodes GlobalId (if :id) or uses the raw value
  4. Fetches from the database using the schema's configured repo

type(name, opts \\ [], list)

(macro)

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

visible(func)

(macro)

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
end

Field-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