Never write TypeScript types for GraphQL schema by hand

Why do we want to use TypeScript?
Modern software development best practices require programmers to write tons of code:
- Business logic
- Tests. Unit/Integrational/E2E and even types. Types are tests that can be run in massive amount even before you run your program
Without tests, your system will be doomed to face well-known issues:
- Teams spend most of their time fixing bugs and not adding new features
- Each newly added feature makes every next feature harder to implement
You need to write tons of code to be on top of your game. Don’t make your life harder. Never again write TypeScript types for GraphQL schema by hand.
TypeScript validates, that your program supports the current GraphQL schema. This adds an awesome layer of quality testing for both the front and back ends:
- Your CI/CD can run TypeScript validation and Unit Tests on your repo and detect any schema cracks.
But writing TypeScript types by hand is a tedious task with fragile results.
Why do we want to automate TypeScript generation from GraphQL schema?
GraphQL allows to automatically generate TypeScript types from a schema file. This feature will:
Save your time. Each schema update should be manually validated and checked on errors. Even a small schema can be >1000 lines of TypeScript definitions. And don't forget that on a React frontend you will need to write Apollo React Hooks.
Protect you from human error. GraphQL specification is quite complex and has lots of details. You most likely know the difference between:
offers(input: OffersInput): [ProductOffer]!
and
offers(input: OffersInput): [ProductOffer!]!
But can you reliable validate each such (and dozens of more small) differences on each schema update?
Protect you from GraphQL specification or schema update. GraphQL language specification evolves with time: https://spec.graphql.org/
Your codebase will always be in sync with the latest GraphQL schema. This way you will be protected from an accidental deployment of a breaking change to production. How cool is that? With automatic TypeScript generation, your GraphQL schema becomes a single source of truth for the whole distributed system.
How to setup automatic TypeScript generation from a GraphQL schema
In this article I’m using a Monorepo project setup, e.g., all my packages and projects are stored in a single repo. This way a client app and a backend can have access to one physical copy of GraphQL schema. But you can store your projects wherever you want, just find a way to provide the same GraphQL schema file to your back and front ends.
If you are consuming a third-party API you can consume the current GraphQL schema directly from the endpoint. I will describe the process later.
I highly recommend using the GraphQL Code Generator package.
- Install “devDependencies” to your package (ofc you may use different package versions and plugins)
- Add “graphql-codegen” command to your “package.json” scripts section.
- Create a “codegen.yml” in your package root. This file will provide configuration for your “graphql-codegen” command. Check codegen.yml documentation
“schema” — where the program should search for GraphQL schema files. In this case, our client “order-list-app” searches for a server GraphQL schema in a nearby monorepo package “order-list-backend”. However, if you are consuming a third-party API, then here you should put your URL endpoint.
“documents” — these files look like graphql schema but describe the client’s operations. GraphQL clients use “documents” to form graphql requests and may be omitted on the backend side.
“graphql_api_build/types_and_hooks.tsx” — where to put result
“plugins"— what code should be generated. In this example, I want TypeScript types + Apollo React Hooks. There are no hooks on the backend, so “typescript-react-apollo” plugin could be omitted on a backend.
- And That's It! Use and enjoy the huge amount of types for free. They will test your system from top to bottom.
You should not commit the generated TypeScript files to git
The files will be compiled directly from the graphql schema after “yarn install” or “npm install”, there is no need to commit them. This way your GraphQL schema will be a single source of truth.
You should recompile the TypeScript types on each schema update
If you have updated the schema, you should call your “graphql-codegen” script, to recompile types. Don’t worry to forget it tho. Compiled files are not committed to the repo, CI/CD will recompile them from a scratch and catch the error. You can’t break production with this inconsistent state.
Conclusion
TypeScript code generation is easy to automate and to use. graphql-code-generator has 6k stars on github. This package is polished way above you can realistically write by hand.
With compiled types you will get:
- Fewer bugs
- Faster development
GraphQL is not just “REST with less network traffic”. It’s a much deeper and profound technology.
Thank you for reading,
Your feedback in the comments is highly appreciated.