Skip to content

Commit

Permalink
Merge pull request #4979 from apollographql/sb/directive-edits
Browse files Browse the repository at this point in the history
Edits to short directives article
  • Loading branch information
Stephen Barlow authored Mar 9, 2021
2 parents e1e6989 + 288360b commit 6378cfe
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 27 deletions.
2 changes: 1 addition & 1 deletion docs/source/api/apollo-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ The default value is `true`, **unless** the `NODE_ENV` environment variable is s

<td>

A map of all [custom schema directives](../schema/directives/#using-custom-schema-directives) used in your schema, if any.
A map of all [custom schema directives](../schema/directives/#custom-schema-directives) used in your schema, if any.
</td>
</tr>

Expand Down
93 changes: 67 additions & 26 deletions docs/source/schema/directives.md
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).

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;
Expand All @@ -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
Expand All @@ -57,7 +105,7 @@ const typeDefs = gql`
}
`;
// Provide resolver functions for your schema fields
// Resolvers
const resolvers = {
Query: {
hello: (parent, args, context) => {
Expand All @@ -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/).

0 comments on commit 6378cfe

Please sign in to comment.