Aug 27, 2019

Using Directives in Scaled Apollo GraphQL

A bit ago I wrote about scaling an Apollo GraphQL Server using schema federation. Read that here.

Directives are basically annotations that can be added to any line of a schema, which start up some processing that should be done related to that line. For instance, you can deprecate fields or queries, honor a list of roles needed to view a field, or transform a field. All you have to do is add an annotation on that line in the schema. It’s pretty amazing.

Using Apollo Gateway, the ability to use directives was left out, for now. Understandably too. Apollo Gateway magically orchestrates distributed services of GraphQL schema/resolvers, and somehow allows them to reference each other. See how to create that magic in the blog I wrote, and mentioned earlier. So, that being said, directives were normally a global set of resolvers for any schema to use; So how can we make that work in a distributed system of services?

The monolithic way is to stitch all of our schemas and resolvers into a big ol’ blob, like this:

import { SchemaDirectiveVisitor } from "graphql-tools";

const typeDefs = `
type ExampleType {
  newField: String
  oldField: String @deprecated(reason: "Use \`newField\`.")
}`;

const schema = makeExecutableSchema({
  typeDefs,
  schemaDirectives: {
    deprecated: DeprecatedDirective
  }
});

class DeprecatedDirective extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>) {
    field.isDeprecated = true;
    field.deprecationReason = this.args.reason;
  }

  public visitEnumValue(value: GraphQLEnumValue) {
    value.isDeprecated = true;
    value.deprecationReason = this.args.reason;
  }
}

The normal way of creating directives is by building a class, override some functions, and inject that into the Apollo instance. Any time that the directive is visited in the schema, your directive class will be invoked and your function will run, allowing you to transform the field in any way.

Okay, so, to create a distributed set of Apollo services that can use directives, we can’t go the normal route. Unfortunately we can’t inject schemaDirectives into buildFederatedSchema, like we did with makeExecutableSchema. The buildFederatedSchema function ignores the schemaDirectives object, and I believe that is because Apollo has not yet settled on the way that they intend to enable directives in federated schemas. To get the job done, we have to rely on an old feature of Apollo that allows us to attach directives to a schema. Import and use the attachDirectiveResolvers as shown below:

const {attachDirectiveResolvers} = require('graphql-tools');
const typeDefs = gql `
directive @upper on FIELD_DEFINITION
... rest of schema ...
`;
const directiveResolvers = {
    upper(next, src, args, context) {
        return next().then((str) => {
            if (typeof(str) === 'string') {
                return str.toUpperCase();
            }
            return str;
        });
}
const schema = buildFederatedSchema([
    {
        typeDefs,
        resolvers,
    }
]);
attachDirectiveResolvers(
    schema,
    directiveResolvers,
);
const server = new ApolloServer({
    schema
});

About the Author

Corey Webster profile.

Corey Webster

Sr. Consultant
Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Feature Flags in Terraform
Feature flagging any code can be useful to developers but many don’t know how to or even that you can do it in Terraform. Some benefits of Feature Flagging your code You can enable different […]
Infrastructure as Code – The Wrong Way
You are probably familiar with the term “infrastructure as code”. It’s a great concept, and it’s gaining steam in the industry. Unfortunately, just as we had a lot to learn about how to write clean […]
Snowflake CI/CD using Jenkins and Schemachange
CI/CD and Management of Data Warehouses can be a serious challenge. In this blog you will learn how to setup CI/CD for Snowflake using Schemachange, Github, and Jenkins. For access to the code check out […]
How to get your pull requests approved more quickly
TL;DR The fewer reviews necessary, the quicker your PR gets approved. Code reviews serve an essential function on any software codebase. Done right, they help ensure correctness, reliability, and maintainability of code. On many teams, […]