GreenFairy.Relay (GreenFairy v0.3.0)

View Source

Relay specification support for GreenFairy.

This module provides full Relay compliance including:

  • Global Object Identification - Globally unique IDs and the node query
  • Cursor Connections - Pagination with edges, cursors, and page info
  • Mutations - Input/payload pattern with clientMutationId

Quick Start

1. Enable Relay in your Schema

defmodule MyApp.GraphQL.Schema do
  use GreenFairy.Schema, discover: [MyApp.GraphQL]
  use GreenFairy.Relay

  # Optional: Configure the repo for node resolution
  @relay_repo MyApp.Repo
end

2. Define Node-implementing Types

defmodule MyApp.GraphQL.Types.User do
  use GreenFairy.Type
  import GreenFairy.Relay.Field

  type "User", struct: MyApp.User do
    implements GreenFairy.BuiltIns.Node

    # Generates globally unique ID
    global_id :id

    # Optional: Custom node resolver
    node_resolver fn id, _ctx ->
      MyApp.Accounts.get_user(id)
    end

    field :email, :string
    field :name, :string

    # Relay connections work seamlessly
    connection :friends, MyApp.GraphQL.Types.User do
      edge do
        field :since, :datetime
      end
    end
  end
end

3. Define Relay Mutations

defmodule MyApp.GraphQL.Mutations.UserMutations do
  use GreenFairy.Mutation
  import GreenFairy.Relay.Mutation

  mutations do
    relay_mutation :create_user do
      input do
        field :email, non_null(:string)
        field :name, :string
      end

      output do
        field :user, :user
      end

      resolve fn input, _ctx ->
        case MyApp.Accounts.create_user(input) do
          {:ok, user} -> {:ok, %{user: user}}
          {:error, _} -> {:error, "Failed to create user"}
        end
      end
    end
  end
end

Features

Global IDs

The global_id macro generates a field that returns a Base64-encoded ID containing both the type name and local ID:

global_id :id                    # Uses struct's :id field
global_id :id, source: :uuid     # Uses a different field
global_id :id, type_name: "User" # Override type name

Decode global IDs with GreenFairy.Relay.GlobalId:

GlobalId.decode("VXNlcjoxMjM=")
#=> {:ok, {"User", "123"}}

Node Query

The node query fetches any object by its global ID:

query {
  node(id: "VXNlcjoxMjM=") {
    id
    ... on User {
      email
    }
  }
}

Connections

Use the connection macro for Relay-compliant pagination:

connection :posts, MyApp.GraphQL.Types.Post

This generates:

  • PostsConnection type with edges and pageInfo
  • PostsEdge type with node and cursor
  • Standard pagination arguments (first, after, last, before)

Mutations

Use relay_mutation for Relay-compliant mutations with clientMutationId:

relay_mutation :update_user do
  input do
    field :id, non_null(:id)
    field :name, :string
  end

  output do
    field :user, :user
  end

  resolve fn input, ctx -> ... end
end

Modules

See Also

Summary

Functions

__using__(opts \\ [])

(macro)

Enables full Relay support in your schema.

This macro adds:

  • node(id: ID!) query field
  • nodes(ids: [ID!]!) query field
  • Node interface resolution

Options

  • :repo - Ecto repo for default node resolution

Example

defmodule MyApp.Schema do
  use GreenFairy.Schema, discover: [MyApp.GraphQL]
  use GreenFairy.Relay, repo: MyApp.Repo
end

decode_id(global_id)

See GreenFairy.Relay.GlobalId.decode/1.

decode_id!(global_id)

See GreenFairy.Relay.GlobalId.decode!/1.

encode_id(type, local_id)

See GreenFairy.Relay.GlobalId.encode/2.