diff --git a/docs/source/api/apollo-server.md b/docs/source/api/apollo-server.md
index 941e2a0f18d..5ff97ee9885 100644
--- a/docs/source/api/apollo-server.md
+++ b/docs/source/api/apollo-server.md
@@ -141,7 +141,7 @@ The default value is `true`, **unless** the `NODE_ENV` environment variable is s
-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.
|
diff --git a/docs/source/schema/directives.md b/docs/source/schema/directives.md
index 834a6960dfa..98f1fa4f00a 100644
--- a/docs/source/schema/directives.md
+++ b/docs/source/schema/directives.md
@@ -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;
@@ -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/).