Code Generation
We use code generation to automatically generate API schemas and type-safe clients for all API integrations. All generated files are ignored by git to reduce noise, make reviews easier on PRs, and only request code reviews from relevant teams.
You will need java
installed on your machine to be able to run the yarn codegen
command, more precisely the openapi-generator
sub-command. Find more about the installation here.
Understanding how code generation works
We are only tracking file that are coming from an external source, e.g. contentfulTypes.d.ts
which depends on Contentful to be generated. The same goes for openapi.yaml
files from external services.
Running yarn codegen
will generate all the schemas and clients for the project. It can take up to 10 minutes to run. The output of each step is cached by NX and subsequent runs will usually be much faster.
In our GitHub workflows, we are caching theses generated files to avoid to re-generate them at each push. However, the generated files have to be updated when some specific files are changed (e.g. *.resolvers.ts
, *.dto.ts
, etc). There is a hashFiles variable in our GitHub workflows which contain a list of file patterns which may affect code generation† and are used to invalidate the cache. You should follow this naming convention for files which need to invalidate the code generation cache.
Code generation build targets
We have 3 different targets that can be configured inside project.json
to generate schemas and types.
codegen/backend-client
codegen/backend-schema
codegen/frontend-client
These are designed with smart defaults and run in the correct order thanks to the NX dependency graph.
Generating schema and client types
If you are changing some API service, you may need to re-generate the API schema using:
With an updated API schema, you may need to re-generate client code with:
If you have changed a public API schema, you may need to re-generate front-end client code with:
Configuring code generation
The following guides cover how to set up code generation in your project.
Generate OpenAPI schemas for your API project
First, you need to create an openApi.ts
file to define the document builder. Add this file to the src
directory of your project alongside the index.ts
.
Next, we need to create an buildOpenApi.ts
that will consume the previous file and generate the openapi.yaml
file.
Finally, we set up a codegen/backend-schema
script in project.json
for the project.
If your service is running a service like redis, you will need to ignore it for running the build-open-api script like follow in the project.json
and in the module where the redis manager is defined
Generate GraphQL schema for your API project
This is similar to generating OpenAPI schemas. Configure your app module to generate a schema file at startup like this:
For the codegen/backend-schema
build target, you can use the build-graphql-schema.ts utility to load your AppModule and generate the GraphQL schema:
Generate an OpenAPI client for a monorepo API
You can use OpenAPI Generator and the OpenAPI schema generated above to generate a type-safe client library to integrate with it. Just create a client project and add the following target to the project.json
.
You'll also need to add an implicit dependency from the client project to the API project (also in project.json
. This is to make sure NX first runs the schema target of the API project before running the client target of the client project.
Generate an OpenAPI client for an external REST API
Creating client libraries for external APIs is similar. You should ask the API provider for an OpenAPI schema and add it to our monorepo in your client project. Name it something like clientConfig.json
(don't name it openapi.yaml
which is ignored by git). Then add a codegen/backend-client
build target project.json
:
In many cases you can download the OpenAPI schema directly from running servers. In that case it is handy to define a update-openapi-document
build target in the client project. Something like this:
In case the API is on X-Road / Straumurinn and you're running xroad proxy, you can fetch OpenAPI schemas for REST APIs with a build target like this:
Generate GraphQL types and hooks
You can use GraphQL Code Generator to generate all kinds of TypeScript types and even React hooks to integrate with GraphQL APIs.
Create a codegen.yml
file in your project:
Finally, you can configure a codegen/frontend-client
inside your project.json
You should use one of the following names for generated files so they're ignored by git:
schema.ts
possibleTypes.json
fragmentTypes.json
*.generated.ts
Instead of generating one big TypeScript file in each project, you might want to use the near-operation-file
preset. It creates small TypeScript files with hooks and operation types for operations defined in graphql files. These can be next to where they're used.
Make sure to configure the codegen/frontend-client
outputs to match:
You can also use GraphQL Code Generator to integrate a GraphQL API inside a backend client project. You can explore which plugins and presets are available. In the least you can use it to validate your operations against the schema, and generate TypeScript types which you then use manually, eg with Enhanced Fetch.
The main thing is to configure the codegen build target as codegen/backend-client
instead of codegen/frontend-client
.
Last updated