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.