Table of Contents

Directives

@deprecated(reason: 'This is just an example')

Directives are part of the GraphQL spec and the recommended way to extend GraphQL’s behaviors.

In this gem, directives are fully event-driven. The idea is to explore the events as much as possible, for both definition and execution scopes, to create an ecosystem of shareable features. Several decisions were made to provide the right environment for directives.

Creating a Directive

You can create your own directive by simply extending the GraphQL::Directive class. As long as the file is properly loaded or added as a dependency, it will be added to the Type Map and ready to use.

# app/graphql/directives/awesome_directive.rb
module GraphQL
  class AwesomeDirective < GraphQL::Directive
    placed_on :object

    on(:attach) do |source|
      puts "I've been added to #{source.name}"
    end
  end
end

Whenever an object requires using this directive, the :attach event will be triggered, and you will be able to access several things from the event and manipulate the object it was attached to.

Read more about events.

Description

Allows documenting directives. This value can be retrieved using introspection or during a to_gql output. Within the class, desc works as a syntax sugar for self.description = ''. It also supports descriptions from I18n.

# app/graphql/directives/awesome_directive.rb
module GraphQL
  class AwesomeDirective < GraphQL::Directive
    desc 'This is awesome!'
  end
end

Repeatability

By default, directives must be unique when applied to anything. However, you can change that behavior by marking that your directive can be repeated in a given location.

# app/graphql/directives/awesome_directive.rb
self.repeatable = true

Arguments

Arguments can help you control what exactly the directive should do. Definition-based directives can use arguments during the :attach event, and execution-based directives can use during any of the events of a request.

# app/graphql/directives/awesome_directive.rb
argument :name, :string, null: false

on(:attach) do |source, name:|
  puts "I've been added to #{source.name}, that provided #{name}"
end

Read more about arguments, events, and request.

Restrictions

All directives must have locations where they can be used. You must call placed_on with the list of acceptable locations.

# app/graphql/directives/awesome_directive.rb
placed_on :object

When creating a directive that will affect the definition of you GraphQL schema, use one or more fo these options:

:schema
Applies to Schemas
:scalar
Applies to Scalars
:object
Applies to Objects
:field_definition
Applies to any Output Fields
:argument_definition
Applies to any Arguments
:interface
Applies to Interfaces
:union
Applies to Unions
:enum
Applies to Enums
:enum_value
Applies to a value of an Enum
:input_object
Applies to Inputs
:input_field_definition
Applies to any Input Fields

When creating a directive that will affect the execution of your GraphQL documents, use one or more fo these options:

:query
Applies to Queries
:mutation
Applies to Mutations
:subscription
Applies to Subscriptions
:field
Applies to any Output Field
:fragment_definition
Applies to Fragments
:fragment_spread
Applies to Spreads for Fragments
:inline_fragment
Applies to Inline Spreads

Hidden

Unavailable This feature is yet to be published.

The hidden setting allow you to use directives and types that will never be exposed to a request. It enables you to use the GraphQL structure to meta-configure itself, like with authorization.

# app/graphql/directives/authorize.rb
self.hidden = true

Beware even if a directive is marked as hidden, it will still be published to the Type Map, which may cause unexpected overrides. To avoid that, use an isolated namespace.

Using Directives

Definitions

To use directives on the definitions of your schema, you can call use to set up a new directive or append a new directive instance to that class.

# This will set up a new instance
use :awesome, name: 'User'

# This will append the instance
use GraphQL::AwesomeDirective.new(name: 'User')

# This is the same as the above
use GraphQL::AwesomeDirective(name: 'User')

As a recommendation, it is always better not to reference the classes directly, so the first approach is preferable.

Read more about recommendations.

Executions

To use directives on the execution of your requests, you can use the @ syntax to add it where you want to use it.

query($public: Boolean!) {
  user {
    id @skip(if: $public)
    name
  }
}

Available Directives

Several other directives are already planned to be added to this gem.

Here is a list of all available directives in this gem:

From the Spec

@deprecated

Indicate deprecated portions of a GraphQL service’s schema, such as deprecated fields or deprecated enum values.

placed_on:
:field_definition, :enum_value
repeatable
false
Arguments
reason: String
Explain why the underlying element was marked as deprecated. If possible, indicate what element should be used instead. This description is formatted using Markdown syntax (as specified by CommonMark).
use :deprecated, reason: 'Too old'

Fields and enum values provide an additional setting called :deprecated that works as a shortcut to add a deprecated directive to them.

This directive works as a simple warning. When used, everything queried that returns deprecated elements get an error message, as in:

{
  "data": {
    "username": "john.doe"
  },
  "errors": [
    {
      "message": "The username field is deprecated, reason: Too old."
    }
  ]
}

@include

Allows for conditional inclusion during execution as described by the if argument.

placed_on:
:field, :fragment_spread, :inline_fragment
repeatable
false
Arguments
if: Boolean!
When false, the underlying element will be automatically marked as null.
query($private: Boolean!) {
  user {
    id @include(if: $private)
    name
  }
}

When if is true:

{ "data": { "user": { "id": "1", "name": "John Doe" } } }

When if is false:

{ "data": { "user": { "name": "John Doe" } } }

@skip

Allows for conditional exclusion during execution as described by the if argument.

placed_on:
:field, :fragment_spread, :inline_fragment
repeatable
false
Arguments
if: Boolean!
When true, the underlying element will be automatically marked as null.
query($public: Boolean!) {
  user {
    id @skip(if: $public)
    name
  }
}

When if is true:

{ "data": { "user": { "name": "John Doe" } } }

When if is false:

{ "data": { "user": { "id": "1", "name": "John Doe" } } }

@specifiedBy

A built-in directive used within the type system definition language to provide a scalar specification URL for specifying the behavior of custom scalar types.

placed_on:
:scalar
repeatable
false
Arguments
url: String!
Point to a human-readable specification of the data format.
use :specified_by, url: 'https://www.rfc-editor.org/rfc/rfc3339'

This directive has no effect whatsoever, and its only purpose is to be displayed in the introspection or during a to_gql output.