DEV Community

Mandi Wise
Mandi Wise

Posted on

Validating GraphQL Operations with a GitHub Action

One of the promises of GraphQL is that it makes it easier to evolve your API on an ongoing basis in comparison to other approaches (like REST APIs). While API maintainers should still avoid making sudden breaking changes to supported types and fields, if you're building a client application it's nonetheless a good idea to make sure that all of the operations it uses can be safely made against the current iteration of the GraphQL API to which it's making its requests.

GitHub Actions provide a convenient way to hook into specific activities in a GitHub repository (for example, pushing or making a pull request) to ensure the GraphQL operations are valid at the time that event occurs. In this post, I'll outline how I built a custom GitHub Action to perform static analysis of all the GraphQL operations used by a client against a GraphQL schema. I'll also provide a demo of how to use this action in your workflows.

TL;DR: You can view the action repo here and a working demo of it in a workflow here.

Action Goals & Game Plan

I had the following high-level goals in mind when I created this action:

  • Search for and validate all GraphQL operations in either .graphql files or in .js files that contain the gql template tag
  • Specify a directory in the project from which to begin recursively searching for operations (to narrow the search)
  • Exclude directories or files from this search as needed
  • Validate operations against a schema file co-located in the repository or a remote schema
  • Send a token in an Authorization header when fetching the schema as needed

To accomplish these goals, I leaned heavily on the GraphQL.js and GraphQL Tools libraries. Specifically, GraphQL Tools provides functions for loading GraphQL operations from either code files (i.e. .js files) or .graphql files. It also provides functions for loading a schema from either a .graphql file, a .json file, or from an URL. The GraphQL.js library provides a function that validates the loaded operation documents against the loaded schema.

I then used the @actions/core package to put the pieces together and run the validation whenever the action is triggered and provide some feedback in the GitHub repository interface about the success or failure of the validation check, including what fields or types are invalid.

Using the Action in a Workflow

You'll first need to create a YAML file to describe the workflow in your project (for example, .github/workflows/operations.yml).

Next, add a job to the file that uses the actions/checkout package to check out your repository's files (which adds them to the $GITHUB_WORKSPACE). You can then run the validation action on the checked-out files as the job's second step.

I designed the GraphQL operation validation action to support the following inputs:

  • base_dir (required): The base directory to search for operations (relative to repository's root directory)
  • schema_location (required): An endpoint URL or path of a .json/.graphql file (relative to repository's root directory)
  • excluded_paths: A comma-separated list of directory/file paths in the base_dir to exclude (relative to base_dir)
  • token: A token to use with an Authorization header (only the Bearer scheme is supported)

This example illustrates how you would validate the GraphQL operations whenever you push or make a pull request to the main branch of a repository. The action points to a local schema file in the repository at swapi/schema.graphql, looks for operations in the swapi directory, and excludes the swapi/schema.graphql file when searching for operations documents (because this would result in an error):

name: Validate GraphQL Operations
on:
  pull_request:
  push:
    branches:
      - main

jobs:
  operations:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo
        uses: actions/checkout@v2

      - name: Validate SWAPI operations
        uses: mandiwise/graphql-operation-validation-action@v1
        with:
          schema_location: ${{ github.workspace }}/swapi/schema.graphql
          base_dir: ${{ github.workspace }}/swapi
          excluded_paths: schema.graphql

At a minimum, you must specify the ${{ github.workspace }} as your base_dir input when using actions/checkout, but you may wish to narrow the search to a specific subdirectory in the project that all operations are nested below. The node_modules directory is automatically ignored when searching for operations, so you don't need to include it in the optional excluded_paths input.

Now when you push to the main branch or a PR is submitted you can check the Actions tab of your repository on GitHub to see the result. If any operations are invalid, then they will be noted in the log.

Send an Auth Token

If you need to validate your operations against a schema that requires a token in an Authorization header, then you can add it as a token input value:

# ...
  - name: Validate GitHub GraphQL API operations
    uses: mandiwise/graphql-operation-validation-action@v1
    with:
      schema_location: https://api.github.com/graphql
      base_dir: ${{ github.workspace }}/github
      token: ${{ secrets.ACCESS_TOKEN }}

The header will be sent using the Authorization: Bearer token... scheme only. You can refer to GitHub's documentation on using encrypted secrets in a workflow to safely store your token with the client application's repository.

Run It Locally

Want to validate your operations in your development environment or without pushing to your repository? No problem!

You can use act to run this action locally. After installing act, you can use act push to run this action on the previous workflow example in your local environment but without actually pushing any code to GitHub. This can be very handy for testing out changes to your GraphQL operations locally during ongoing development to your client application.

Good to Know

Because an introspection query is required to get the schema, introspection must be turned on for the GraphQL API you wish to validate your operations against. For this reason, the action is probably best-suited for use with a public GraphQL API, in your local development environment, or when the schema file is co-located with your client application.

Summary

This action was my first foray into GitHub Actions and I learned a lot throughout the process of developing it. GitHub Actions are very powerful and I found it a bit tricky at first to grok all of the moving parts and know where to start when creating a custom action, but with just a couple hundred lines of code, I hope this action provides a useful reference for you if you're interested in creating your own.

If you use this action in any of your GraphQL-related workflows I'd love to hear any feedback you have about it in the comments on this post or in the repo's Issues.

Top comments (0)