Directives are system-defined keywords with two kinds of uses:
Runtime directives are server-defined keywords that modify GraphQL execution. All GraphQL systems have at least two directives, @skip
and @include
. For example:
query ProfileView($renderingDetailedProfile: Boolean!){
viewer {
handle
# These fields will be included only if the check passes:
... @include(if: $renderingDetailedProfile) {
location
homepageUrl
}
}
}
Here’s how the two built-in directives work:
@skip(if: ...)
skips the selection if the if: ...
value is truthy (GraphQL::Schema::Directive::Skip
)@include(if: ...)
includes the selection if the if: ...
value is truthy (GraphQL::Schema::Directive::Include
)Custom directives extend GraphQL::Schema::Directive
:
# app/graphql/directives/my_directive.rb
class Directives::MyDirective < GraphQL::Schema::Directive
description "A nice runtime customization"
location FIELD
end
Then, they’re hooked up to the schema using directive(...)
:
class MySchema < GraphQL::Schema
# Attach the custom directive to the schema
directive(Directives::MyDirective)
end
And you can reference them in the query with @myDirective(...)
:
query {
field @myDirective {
id
}
}
GraphQL::Schema::Directive::Feature
and GraphQL::Schema::Directive::Transform
are included in the library as examples.
Directive classes may implement the following class methods to interact with the runtime:
def self.include?(obj, args, ctx)
: If this hook returns false
, the nodes flagged by this directive will be skipped at runtime.def self.resolve(obj, args, ctx)
: Wraps the resolution of flagged nodes. Resolution is passed as a block, so yield
will continue resolution.Looking for a runtime hook that isn’t listed here? open an issue to start the conversation!
Schema directives are used in GraphQL’s interface definition language (IDL). For example, @deprecated
is built in to GraphQL-Ruby:
type User {
firstName @deprecated(reason: "Use `name` instead")
lastName @deprecated(reason: "Use `name` instead")
name
}
In the schema definition, directives express metadata about types, fields, and arguments.
To make a custom schema directive, extend GraphQL::Schema::Directive
:
# app/graphql/directives/permission.rb
class Directives::Permission < GraphQL::Schema::Directive
argument :level, String
locations FIELD_DEFINITION, OBJECT
end
Then, attach it to parts of your schema with directive(...)
:
class Types::JobPosting < Types::BaseObject
directive Directives::Permission, level: "manager"
end
Arguments and fields also accept a directives:
keyword:
field :salary, Integer, null: false,
directives: { Directives::Permission => { level: "manager" } }
After that:
.directives
method will return an array containing an instance of the specified directiveSchema.to_definition
) will include the configured directivesSimilarly, Schema.from_definition
parses directives from IDL strings.
For a couple of built-in examples, check out:
GraphQL::Schema::Directive::Deprecated
which implements deprecation_reason
(via GraphQL::Schema::Member::HasDeprecationReason
)GraphQL::Schema::Directive::Flagged
, which is an example of using schema directives to implement visibilityBy default, the directive’s name is taken from the class name. You can override this with graphql_name
, for example:
class Directives::IsPrivate < GraphQL::Schema::Directive
graphql_name "someOtherName"
end
Like fields, directives may have arguments :
argument :if, Boolean,
description: "Skips the selection if this condition is true"