Analyzing code for compliance with guidelines is one part of the code quality assuarance and automating it with tools like ESLint and binding the checks with build process is common and routine operation. But what about validating GraphQL schema and queries? Here are some pointers to tools you can use to start linting your GraphQL schema.
Resources:
- eslint-plugin-graphql: Checks tagged query strings inside JavaScript, or queries inside .graphql files, against a GraphQL schema.
- graphql-eslint: Lints both GraphQL schema and GraphQL operations.
- graphql-schema-linter: Command line tool to validate GraphQL schema definitions against a set of rules.
- apollo-tooling: Brings together your GraphQL clients and servers with tools for validating your schema, linting your operations and generating static types.
Using ESLint for GraphQL checks
Depending of you project structure and how you’ve created your schema and queries you can use different tools for linting it. eslint-plugin-graphql requires you to have the schema ready whereas graphql-eslint can do some checks and validation without the schema.
Using the graphql-eslint and configuration in package.json where the project uses code files to store GraphQL schema / operations:
"eslintConfig": {
...
"overrides": [
{
"files": [
"*.js"
],
"processor": "@graphql-eslint/graphql"
},
{
"files": [
"*.graphql"
],
"parser": "@graphql-eslint/eslint-plugin",
"plugins": [
"@graphql-eslint"
],
"rules": {
"prettier/prettier": "off",
"@graphql-eslint/unique-fragment-name": "warn",
"@graphql-eslint/no-anonymous-operations": "warn",
"@graphql-eslint/no-operation-name-suffix": "error",
"@graphql-eslint/no-case-insensitive-enum-values-duplicates": [
"error"
]
}
}
]
}
Linting process can be enriched and extended with GraphQL type information, if you are able to provide your GraphQL schema.
Introspection Query and schema linting
GraphQL APIs are required to be self-documenting and every standard conforming GraphQL API needs to respond to queries about its own structure. This system is called introspection. The key for GraphQL validation is doing the introspection query and getting the schema in GraphQL Schema Definition Language format. The query gets you the JSON representation of the shape of the API which you can convert to SDL. See more about GraphQL Schemas.
You can use the apollo-tooling for the introspection. First start your GraphQL service and point the apollo to it.
npx apollo client:download-schema --endpoint=http://localhost:4444/graphql schema.graphql
The tooling outputs in this case the schema in GraphQL SDL format (.graphql) and you can also get it in JSON by using the schema.json
filename.
Now that you have the GraphQL schema you can lint it by using graphql-schema-linter. Create config graphql-schema-linter.config.js
in your project root folder.
module.exports = {
rules: ['enum-values-sorted-alphabetically'],
schemaPaths: ['path/to/my/schema/files/**.graphql'],
customRulePaths: ['path/to/my/custom/rules/*.js'],
rulesOptions: {
'enum-values-sorted-alphabetically': { sortOrder: 'lexicographical' }
}
};
And run graphql-schema-linter
You get results e.g.
1320:1 The type `Upload` is defined in the schema but not used anywhere. defined-types-are-used 74:3 The field `Company.phone_number` is not camel cased. fields-are-camel-cased
Running graphql-schema-linter in CI/CD
For automating schema checks you can use the graphql-schema-linter
in your CI/CD pipeline. Here’s an example for GitLab CI where we run our GraphQL service inside docker.
docker-compose-introspection.yml:
version: '3.1'
services:
service-graphql-introspection:
image: node:14-alpine
container_name: graphql-service-introspection
restart: unless-stopped
environment:
NODE_ENV: development
ENVIRONMENT: introspection
PORT: 4000
ports:
- "4000:4000"
user: node
volumes:
- ./:/home/node
working_dir: /home/node
command: "npm run start:docker"
Where npm run start:docker
is "./node_modules/nodemon/bin/nodemon.js --legacy-watch --exec ./node_modules/@babel/node/bin/babel-node.js src/app.js"
gitlab-ci.yml:
run_test:
image: docker:19.03.1
stage: test
services:
- docker:19.03.1-dind
before_script:
- apk add --no-cache docker-compose npm
script:
- "# Start GQL"
- docker-compose -f docker-compose-introspection.yml up -d
- "# Get introspection schema"
- cd /tmp
- npx apollo client:download-schema --endpoint=http://localhost:4000/graphql schema.graphql
- cd $CI_PROJECT_DIR
- docker-compose -f docker-compose-introspection.yml stop
- docker-compose -f docker-compose-introspection.yml rm -f
- "# Run tests"
- npx graphql-schema-linter /tmp/schema.graphql
The results in CI/CD pipeline could look then like this:
Leave a Reply