-
Notifications
You must be signed in to change notification settings - Fork 2k
Edits to short directives article #4979
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,88 @@ | ||
--- | ||
title: Using schema directives | ||
description: Using schema directives to transform schema types, fields, and arguments | ||
title: Directives | ||
sidebar_title: Directives | ||
description: Configure GraphQL types, fields, and arguments | ||
--- | ||
|
||
A _directive_ is an identifier preceded by a `@` character, optionally followed by a list of named arguments, which can appear after almost any form of syntax in the GraphQL query or schema languages. Here's an example from the [GraphQL draft specification](http://facebook.github.io/graphql/draft/#sec-Type-System.Directives) that illustrates several of these possibilities: | ||
A **directive** decorates part of a GraphQL schema or operation with additional configuration. Tools like Apollo Server (and [Apollo Client](https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#querying)) can read a GraphQL document's directives and perform custom logic as appropriate. | ||
|
||
```typescript | ||
Directives are preceded by the `@` character, like so: | ||
|
||
```graphql{2}:title=schema.graphql | ||
type ExampleType { | ||
oldField: String @deprecated(reason: "Use `newField`.") | ||
newField: String | ||
} | ||
``` | ||
|
||
This example shows the `@deprecated` directive, which is a [default directive](#default-directives) (i.e., it's part of the [GraphQL specification](http://spec.graphql.org/June2018/#sec--deprecated)). It demonstrates the following about directives: | ||
|
||
* Directives can take arguments of their own (`reason` in this case). | ||
* Directives appear _after_ the declaration of what they decorate (the `oldField` field in this case) | ||
|
||
## Valid locations | ||
|
||
Each directive can only appear in _certain_ locations within a GraphQL schema or operation. These locations are listed in the directive's definition. | ||
|
||
For example, here's the GraphQL spec's definition of the `@deprecated` directive: | ||
|
||
```graphql | ||
directive @deprecated( | ||
reason: String = "No longer supported" | ||
) on FIELD_DEFINITION | ENUM_VALUE | ||
``` | ||
|
||
type ExampleType { | ||
newField: String | ||
oldField: String @deprecated(reason: "Use `newField`.") | ||
This indicates that `@deprecated` can decorate either a schema `FIELD_DEFINITION` (as shown at the top of the article) or a schema `ENUM_VALUE` definition (as shown here): | ||
|
||
```graphql:title=schema.graphql | ||
enum MyEnum { | ||
OLD_VALUE @deprecated(reason: "Use `NEW_VALUE`.") | ||
NEW_VALUE | ||
} | ||
``` | ||
|
||
As you can see, the usage of `@deprecated(reason: ...)` _follows_ the field that it pertains to (`oldField`), though the syntax might remind you of "decorators" in other languages, which usually appear on the line above. Directives are typically _declared_ once, using the `directive @deprecated ... on ...` syntax, and then _used_ zero or more times throughout the schema document, using the `@deprecated(reason: ...)` syntax. | ||
If `@deprecated` appears elsewhere in a GraphQL document, it produces an error. | ||
|
||
> If you [create a custom directive](#custom-schema-directives), you need to define it (and its valid locations) in your schema. You don't need to define [default directives](#default-directives) like `@deprecated`. | ||
|
||
### Schema directives vs. operation directives | ||
|
||
Usually, a given directive appears _exclusively_ in GraphQL schemas or _exclusively_ in GraphQL operations (rarely both, although the spec allows this). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that the implementing directives page calls these query directives. I think moving towards operation rather than query is good, though, and I think you said you were heading to that page next. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, I'll replicate this change over there. |
||
|
||
For example, among the [default directives](#default-directives), `@deprecated` is a schema-exclusive directive and `@skip` and `@include` are operation-exclusive directives. | ||
|
||
The [GraphQL spec](https://spec.graphql.org/June2018/#sec-Type-System.Directives) lists all possible directive locations. Schema locations are listed under `TypeSystemDirectiveLocation`, and operation locations are listed under `ExecutableDirectiveLocation`. | ||
|
||
## Default directives | ||
|
||
The [GraphQL specification](http://spec.graphql.org/June2018/#sec-Type-System.Directives) defines the following default directives: | ||
|
||
## Default Directives | ||
| Directive | Description | | ||
|-----------|-------------| | ||
| `@deprecated(reason: String)` | Marks the schema definition of a field or enum value as deprecated with an optional reason. | | ||
| `@skip(if: Boolean!)` | If `true`, the decorated field or fragment in an operation is _not_ resolved by the GraphQL server. | | ||
| `@include(if: Boolean!)` | If `false`, the decorated field or fragment in an operation is _not_ resolved by the GraphQL server. | | ||
|
||
GraphQL provides several default directives: [`@deprecated`](http://facebook.github.io/graphql/draft/#sec--deprecated), [`@skip`](http://facebook.github.io/graphql/draft/#sec--skip), and [`@include`](http://facebook.github.io/graphql/draft/#sec--include). | ||
## Custom schema directives | ||
|
||
* [`@deprecated`](http://facebook.github.io/graphql/draft/#sec--deprecated)`(reason: String)` - marks field as deprecated with message | ||
* [`@skip`](http://facebook.github.io/graphql/draft/#sec--skip)`(if: Boolean!)` - GraphQL execution skips the field if true by not calling the resolver | ||
* [`@include`](http://facebook.github.io/graphql/draft/#sec--include)`(if: Boolean!)` - Calls resolver for annotated field if true | ||
You can extend Apollo Server with custom schema directives created by you or a third party. | ||
|
||
## Using custom schema directives | ||
> To learn how to create custom directives, see [implementing directives](./creating-directives/). | ||
|
||
To use a custom schema directive, pass the implemented class to Apollo Server via the `schemaDirectives` argument, which is an object that maps directive names to directive implementations: | ||
To use a custom directive: | ||
|
||
```js | ||
1. Make sure the directive is defined in your schema with all valid locations listed. | ||
2. If the directive uses a `SchemaDirectiveVisitor` subclass to perform custom logic, provide it to the `ApolloServer` constructor via the `schemaDirectives` object. | ||
|
||
_The `schemaDirectives` object maps the name of a directive (e.g., `upper`) to the subclass that implements its behavior (e.g., `UpperCaseDirective`)._ | ||
|
||
The following example defines an `UpperCaseDirective` subclass for use with the `@upper` custom directive. Because it's decorated with `@upper`, the `Query.hello` field returns `HELLO WORLD!` instead of `Hello world!`. | ||
|
||
```js{20,40-42} | ||
const { ApolloServer, gql, SchemaDirectiveVisitor } = require('apollo-server'); | ||
const { defaultFieldResolver } = require('graphql'); | ||
|
||
// Create (or import) a custom schema directive | ||
// Subclass definition for @upper directive logic | ||
class UpperCaseDirective extends SchemaDirectiveVisitor { | ||
visitFieldDefinition(field) { | ||
const { resolve = defaultFieldResolver } = field; | ||
|
@@ -48,7 +96,7 @@ class UpperCaseDirective extends SchemaDirectiveVisitor { | |
} | ||
} | ||
|
||
// Construct a schema, using GraphQL schema language | ||
// Schema definition (including custom directive) | ||
const typeDefs = gql` | ||
directive @upper on FIELD_DEFINITION | ||
|
||
|
@@ -57,7 +105,7 @@ const typeDefs = gql` | |
} | ||
`; | ||
|
||
// Provide resolver functions for your schema fields | ||
// Resolvers | ||
const resolvers = { | ||
Query: { | ||
hello: (parent, args, context) => { | ||
|
@@ -78,11 +126,4 @@ const server = new ApolloServer({ | |
server.listen().then(({ url }) => { | ||
console.log(`🚀 Server ready at ${url}`) | ||
}); | ||
|
||
``` | ||
|
||
The implementation of `UpperCaseDirective` takes care of changing the resolver and modifying the schema if necessary. | ||
|
||
## Building your own | ||
|
||
To learn how to implement your own schema directives, read [this guide](/schema/creating-directives/). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may or may not be interesting that this is likely to change to add some more locations (graphql/graphql-spec#805) and that in fact graphql-js and others already support more locations...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, hmm. I'll keep like this for now to match 2018 and might revisit this with additional perspective after cleaning up the big article