Docs
Launch GraphOS Studio
Apollo Server 3 is officially deprecated, with end-of-life scheduled for 22 October 2024. Learn more about upgrading to a supported Apollo Server version.

Creating schema directives

Apply custom logic to GraphQL types, fields, and arguments


Before you create a custom , learn the basics about directives.

Your can define custom s that can then decorate other parts of your :

schema.graphql
# Definition
directive @uppercase on FIELD_DEFINITION
type Query {
# Usage
hello: String @uppercase
}

See an example implementation of this on CodeSandbox:

Edit upper-case-directive

When you start up your app, you can use s to transform your executable 's behavior before you provide that schema to Apollo Server. For example, you can modify the function for any decorated (for the schema above, it could transform the hello 's original result to uppercase).

Defining

A definition looks like this:

schema.graphql
directive @deprecated(
reason: String = "No longer supported"
) on FIELD_DEFINITION | ENUM_VALUE
  • This is the definition for the @deprecated in the GraphQL spec.
  • The takes one optional (reason) with a default value ("No longer supported").
  • The can decorate any number of FIELD_DEFINITIONs and ENUM_VALUEs in your .

Supported locations

Your custom can appear only in the locations you list after the on keyword in the 's definition.

The table below lists all available locations in a GraphQL . Your can support any combination of these locations.

Name /
MapperKind
Description
SCALAR

SCALAR_TYPE

The definition of a custom scalar

OBJECT

OBJECT_TYPE

The definition of an object type

FIELD_DEFINITION

OBJECT_FIELD

The definition of a within any defined type except an input type (see INPUT_FIELD_DEFINITION)

ARGUMENT_DEFINITION

ARGUMENT

The definition of a

INTERFACE

INTERFACE_TYPE

The definition of an interface

UNION

UNION_TYPE

The definition of a union

ENUM

ENUM_TYPE

The definition of an enum

ENUM_VALUE

ENUM_VALUE

The definition of one value within an enum

INPUT_OBJECT

INPUT_OBJECT_TYPE

The definition of an input type

INPUT_FIELD_DEFINITION

INPUT_OBJECT_FIELD

The definition of a within an input type

SCHEMA

ROOT_OBJECT

The top-level schema object declaration with query, mutation, and/or subscription s (this declaration is usually omitted)

Implementing

Important: Apollo Server 3 does not provide built-in support for custom s. To enable this support, you need to install certain @graphql-tools libraries.

This article uses @graphql-tools version 8. Previous versions use a different API for custom s. If you're using an earlier version of @graphql-tools, see the Apollo Server v2 docs.

After you define your and its valid locations, you still need to define the logic that Apollo Server executes whenever it encounters the in your .

To define custom logic with @graphql-tools v8 and later, you can create transformer functions that transform an executable 's behavior based on the s that are present in it.

1. Install required libraries

First, install the following @graphql-tools libraries:

npm install @graphql-tools/schema @graphql-tools/utils

2. Define directive logic

To define what Apollo Server does when it encounters your , you can create a transformer function. This function uses the mapSchema function to iterate through locations in your ( definitions, type definitions, etc.) and perform transformations wherever it encounters a particular (or set of directives).

For example, here's a possible transformer function for the default @deprecated :

directives.js
const { mapSchema, getDirective, MapperKind } = require('@graphql-tools/utils');
function deprecatedDirectiveTransformer(schema, directiveName) {
return mapSchema(schema, {
// Executes once for each object field definition in the schema
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const deprecatedDirective = getDirective(schema, fieldConfig, directiveName)?.[0];
if (deprecatedDirective) {
fieldConfig.deprecationReason = deprecatedDirective['reason'];
return fieldConfig;
}
},
// Executes once for each enum value definition in the schema
[MapperKind.ENUM_VALUE]: (enumValueConfig) => {
const deprecatedDirective = getDirective(schema, enumValueConfig, directiveName)?.[0];
if (deprecatedDirective) {
enumValueConfig.deprecationReason = deprecatedDirective['reason'];
return enumValueConfig;
}
}
});
};

As shown, the second parameter you pass mapSchema is an object with keys that represent one or more locations in your . The MapperKind enum value for each supported location is listed in the table above.

Example: Uppercasing strings

Suppose you want to convert certain String s in your to uppercase before they're returned.

This example defines an @uppercase for this purpose:

This code replaces the of an @uppercase with a new function. This new function first calls the original , then transforms its result to uppercase (assuming it's a string) before returning it.

Additional examples

For additional examples of transforming executable s with s and mapSchema, see the @graphql-tools docs.

What about query directives?

Although syntax can also appear in GraphQL queries sent from the client, implementing query directives requires runtime transformation of query documents. We have deliberately restricted this implementation to transformations that take place at server construction time.

We believe confining this logic to your is more sustainable than burdening your clients with it, though you can probably imagine a similar sort of abstraction for implementing query s. If that possibility becomes a need for you, let us know.

Previous
Directives
Next
Resolvers
Edit on GitHubEditForumsDiscord