Geek Culture
Published in

Geek Culture

GraphQL compatibility testing using Rover CLI and graphql-inspector

Recently I engaged with GraphQL related development and we wanted to do the compatibility testing on the recent development we do. We came across a good approach and thought of sharing that knowledge and experience I gained throughout this story. First of all, let's get to know what is GraphQL and why we need compatibility testing.

GraphQL is a powerful open-source data query and server-side runtime manipulation language for APIs that prioritizes giving clients exactly the data they request and no more. Simply unlike REST APIs in GraphQL, it won’t return the data which are not requested from the client. Hence GraphQL is designed to make the APIs flexible, fast, and more developer-friendly.

In GraphQL we can follow our implementation in federation architecture which is originally introduced by Netflix to make their microservices more loosely coupled and highly scalable by offering a unified API aggregation layer at the edge which can be used by UI developers. Here the implementation has two main parts, one is GraphQL Gateway (supergraph) which is primarily responsible for serving GraphQL queries to the client and the second is the collection of GraphQL services (subgraphs) exposed.

Evolution of an API Architecture
Federated Architecture

Why do we need compatibility tests for GraphQL?

When we develop our queries for GraphQL with the federation architecture it is required to maintain the contract between the GraphQL Gateway and the other GraphQL exposed. It is not a good practice to remove or change the query resolvers or its contract without backward compatibility since it will affect the gateway and the clients who are already consuming it. To address this issue and make the application work smoothly even after a new deployment has taken place it is required to do a compatibility test during the deployment pipeline.

How we can do compatibility tests for GraphQL?

To do the compatibility test the main thing we have to do is compare the existing production environment supergraph which is exposed to the clients with the newly generated supergraph with the new changes made.

Therefore we have to have a tool to generate GraphQL schemas and find the difference. We came across two tools that can be used to this requirement fulfilled.

The Rover CLI

This is a powerful CLI tool that we can use to is for managing and maintaining data graphs with Apollo Studio. We can generate existing and new GraphQL schemas and compose supergraphs using this tool.

graphql-inspector/ci

With @graphql-inspector/ci we can do many CI/CD related schema validation operations. For the compatibility test, we can use this tool to get the difference of supergraphs during the deployment pipeline.

Compatibility test for GraphQL

Lets’s see how we can use these tools to do the compatibility tests for GraphQL implementation which is implemented following federation architecture using apollo federation.

First, we have to download and install Rover CLI. I am using ubuntu and the below command is for ubuntu. You can use other installations according to your Operating System from the link provided.

curl -sSL https://rover.apollo.dev/nix/latest | sh

Then we have to up and run our GraphQL service. My service is written in NodeJs so the command given below is to up and run the node service.

node start

Now assume you have two GraphQL subgraphs and one GraphQL gateway.

https://subgraph-1-production/graphql

https://subgraph-2-production/graphql

In order to fetch the GraphQL schemas of the production, we can use the below commands. Read more...

rover subgraph introspect https://subgraph-1-production/graphql  > prod-subgraph1.graphqlrover subgraph introspect https://subgraph-2-production/graphql  > prod-subgraph2.graphql

Assume we made the change to the subgraph2 service, then we can use the below command to get the newly changed subgraph of subgraph2.

rover subgraph introspect http://localhost:3000/graphql > local-subgraph2.graphql

Now we have all the subgraph schemas that we need to generate existing and new supergraph schema which can be used to validate for compatibility tests.

To generate the supergraph we need an additional config .yaml file which rover refers to use composing the supergraph. These two .yaml contents are given below. Read more…

local-supergraph.yaml

subgraphs:
products:
routing_url: http://localhost:3000/graphql
schema:
file: ./local-subgraph2.graphql
orders:
routing_url: https://subgraph-1-production/graphql
schema:
file: ./prod-subgraph1.graphql

prod-supergraph.yaml

subgraphs:
products:
routing_url: https://subgraph-1-production/graphql
schema:
file: ./prod-subgraph1.graphql
orders:
routing_url: https://subgraph-2-production/graphql
schema:
file: ./prod-subgraph2.graphql

Now we can use these two .yaml files to generate local-supergraph.graphql and prod-supergraph.graphql with the command given below.

rover supergraph compose --config ./local-supergraph.yaml > local-supergraph.graphqlrover supergraph compose --config ./prod-supergraph.yaml > prod-supergraph.graphql

Now we have existing (prod-supergraph.graphql) and new (local-supergraph.graphql) to compare the difference. To compare the difference we can use the graphql-inspector diff command given below. Read more…

graphql-inspector diff prod-supergraph.graphql local-supergraph.graphql

The above command will identify the difference between the two schemas provided (Old-New). GraphQL Inspector defines three kinds of changes:

  • Non-breaking change
  • Dangerous Change
  • Breaking change

When there’s at least one breaking change, the process fails, otherwise, it succeeds.

Now we can use all these commands in the .sh file and execute them along with our test scripts.

compatible_test.sh

curl -sSL https://rover.apollo.dev/nix/latest | shnohup yarn start &
sleep 10
allErrors=""{ err=$(rover subgraph introspect https://subgraph-1-production/graphql 2>&1 >&3 3>&-); } 3> ./tests/prod-subgraph1.graphql
echo $err;
allErrors+="$err"
{ err=$(rover subgraph introspect https://subgraph-2-production/graphql 2>&1 >&3 3>&-); } 3> ./tests/prod-subgraph2.graphql
echo $err;
allErrors+="$err"
{ err=$(rover subgraph introspect https://subgraph-1-production/graphql 2>&1 >&3 3>&-); } 3> ./tests/local-subgraph2.graphql
echo $err;
allErrors+="$err"
{ err=$(rover supergraph compose --config ./tests/prod-supergraph.yaml 2>&1 >&3 3>&-); } 3> ./tests/prod-supergraph.graphql
echo $err;
allErrors+="$err"
{ err=$(rover supergraph compose --config ./tests/local-supergraph.yaml 2>&1 >&3 3>&-); } 3> ./tests/local-supergraph.graphql
echo $err;
allErrors+="$err"
{ err=$(graphql-inspector diff ./tests/prod-supergraph.graphql ./tests/local-supergraph.graphql 2>&1); }
echo $err;
allErrors+="$err"
if [[ $allErrors == *"error"* ]]; then
echo "$(tput setaf 1)compatibility check failed with some errors...$(tput sgr0)"
exit 1
fi

exit 0

If you want to pass some authorizations for your live graph

{ err=$(rover subgraph introspect https://subgraph-1-production/graphql --header “Authorization: Bearer XXXYYYZZZ” 2>&1 >&3 3>&-); } 3> ./tests/prod-subgraph1.graphql

Then run it along with your tests (inside package.json)

"test:compatibility": "sh tests/compatible_test.sh",

This is one out of thousand ways of doing compatibility tests for GraphQL federation implementation. Hope this story will help you to get some idea of doing compatibility tests for your GraphQL implementation. Happy coding…

Thanks For Reading, Follow me for more. If you do have any questions please leave a comment. I will surely answer your questions. If you find this useful for other developers please like and share.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Miraj Hamid

Miraj Hamid

Software Engineer with experience in analysis & design in Java ,Spring-boot, NodeJs & ReactJS | https://www.linkedin.com/in/mirajhamid/