Front-End Web & Mobile

Merging GraphQL schema files and more from the CLI

This post was written by Hani Sehweil, SDET II, Amazon Devices

GraphQL schemas can become really big over time, making them hard to manage as a single file. For example, you may want to break down your GraphQL schema based on team ownership, where each part of the schema may be sourced in a different codebase. However, you want to expose it as a single GraphQL endpoint.

On my team, Amazon Devices, the solution we built works across different GraphQL implementations. We built the solution utilizing graphql-js to build a CLI utility to merge schema files, validate schema, and add your own custom validation rules for schema and operation files.

This post demonstrates these three solutions using the CLI.

Merging schema files

You can merge your schema files across different modules and directories. In this example, you have three different set of files in three different directories:

~/moduleMain/schemas/Root.graphql:
type Query {     
}

~/module1/schemas/Book.graphql:
extend type Query {
  bookById(id: ID!): Book
}
    
type Book {
  id: ID!
  authorId: ID!
}
 
~/module2/schemas/User.graphql:
extend type Query {
  userById(id: ID!): User
}
    
type User {
  id: ID!
  name: String!
}

Running the CLI utility generates the merged schema file, Merged_schema.graphQL:

type Query {
   userById(id: ID!): User
   bookById(id: ID!): Book
 }
 
 type User {
   id: ID!
   name: String!
 }
 
 type Book {
   id: ID!
   authorId: ID!
 }

Before we show how to write the commands, this post assumes that you are familiar with Glob. A glob is a string of both literal and wildcard characters that you can use to match filepaths.

Prerequisites:

  • Install Node.js.
  • Install graphql-schema-utilities: npm install -g graphql-schema-utilities
> graphql-schema-utilities -s “{/module2/schemas/**/*.graphql,/module1/schemas/**/*.graphql,/moduleMain/schemas/**/*.graphql

You can use this tool for Java-based GraphQL services.

You can import the merged schema from your build configuration file from your favorite build automation tool (Gradle, ANT, etc.). It is similar in other languages, as long as you can install Node.js on your local host and run the command line from the coding language that you are using.

Validating schema

The CLI validates the merged GraphQL schema files from having syntax or semantics errors. It also validates the GraphQL operation files against the merged schema to verify that they are valid operations.

For example, if you run the utility against the following GraphQL operation file, it returns an invalid operation error. This error is because the following operation has a variable of type String, while the previous schema, Merged_schema.graphql, expects an ID type.

~/module2/operations/getUserById.graphql:
query userById($id: String!) {
  userById(id: $id) {
    id
    name
  }
}

Customizing your validation rules

The tool validates by default against the set of rules that are defined in graphql-js. However, you can add your own validation rules, as mentioned in the graphql-js documentation on GitHub.

For example, the following custom rule makes sure that operations are invalid unless the name starts with Hawaii_:

### file name: custom_rule.ts

import { GraphQLError } from 'graphql';

export function doesNotStartWithHawaii(operationName: string): string {
  return `"${operationName}" operation does not start with Hawaii_.`;
}

/**
 * Valid only if it starts with Hawaii_.
 * A GraphQL document is only valid if all defined operations starts with Hawaii_.
 */
export function OperationNameStartsWithHawaii(
  context: any,
): ASTVisitor {
  const knownOperationNames = Object.create(null);  
  return {
    OperationDefinition(node) {
      const operationName = node.name;
      if (operationName) {
        if (!operationName.value.startsWith('Hawaii_')) {
          
          context.reportError(
            new GraphQLError(
              doesNotStartWithHawaii(operationName.value)
            ),
          );
        } else {
          knownOperationNames[operationName.value] = operationName;
        }
      }
      return false;
    },
    FragmentDefinition: () => false,
  };
}

Summary:

In this blog we address how graphql-schema-utilities provides solutions to manage your schema files (merge, and validation) in separate files and/or directories. We also show how the CLI tool allows you to run the solution regardless of which programming language is used to implement your GraphQL API.