GraphQL code generator

GraphQL Code Generator is a command-line tool that generates TypeScript typings and helper functions from a GraphQL schema, making it easier for developers to build APIs and services. This document provides guidance on the best practices for using the GraphQL Code Generator with caisy.

For a full working sample of this config, check one of our starter templates such as:

Prerequisites

Make sure you have the APIKEY and PROJECT_ID from caisy. This APIKEY will be used to authenticate your requests to the caisy GraphQL API. We refer to them in the code as environment variables such as CAISY_PROJECT_ID and CAISY_API_KEY and assume you have stored them in the .env file in the root of your project.

Setup

In your project, install the necessary dependencies. The base is @graphql-codegen/cli , but you further need the necessary plugins for generating the code too.

So you decencies might look like this:

npm install @graphql-codegen/cli @graphql-codegen/introspection @graphql-codegen/typed-document-node @graphql-codegen/typescript @graphql-codegen/typescript-generic-sdk @graphql-codegen/typescript-operations --save-dev

Remember to replace CAISY_GQL_ENDPOINT and CAISY_API_KEY with your project-specific values.

Codegen Configuration

In your project, you should have a codegen.ts file that configures the GraphQL Code Generator. This file specifies the GraphQL endpoint to be used, the headers to be sent with requests, and the files that the generator should output. It also defines several settings that control the behavior of the generator.

Below is a sample codegen.ts file configuration:

import { CodegenConfig } from '@graphql-codegen/cli';

export const config: CodegenConfig = {
  overwrite: true,
  ignoreNoDocuments: true,
  schema: [
    {
      [`https://cloud.caisy.io/api/e/v4/${process.env.CAISY_PROJECT_ID}/graphql` || '']: {
        headers: {
          'x-caisy-apikey': `${process.env.CAISY_API_KEY}`,
        },
      },
    },
  ],
  generates: {
    'src/services/graphql/__generated/graphql.schema.json': {
      plugins: ['introspection'],
    },
    'src/services/graphql/__generated/graphql.schema.graphql': {
      plugins: ['schema-ast'],
    },
    'src/services/graphql/__generated/sdk.ts': {
      documents: ['src/services/graphql/**/*.graphql', 'src/services/graphql/fragments/**/*.ts', 'src/services/graphql/queries/**/*.ts'],
      plugins: ['typescript', 'typescript-operations', 'typescript-generic-sdk'],
      config: {
        rawRequest: false,
        inlineFragmentTypes: 'combine',
        skipTypename: false,
        exportFragmentSpreadSubTypes: true,
        dedupeFragments: true,
        preResolveTypes: true,
        typesPrefix: "IGen"
      },
    },
  },
};

export default config;

In the above

configuration, the codegen.ts file specifies the GraphQL endpoint to be used, the headers to be sent with requests, and the files that the generator should output. It also defines several settings that control the behavior of the generator:

  • overwrite: This option allows the generator to overwrite existing files.

  • ignoreNoDocuments: If set to true, the generator will not throw an error if no documents are found.

  • schema: Specifies the endpoint(s) of your GraphQL schema. Headers for the request can be specified in this field. The caisy GraphQL endpoint and API key are specified here.

  • generates: This field specifies the output files and their configurations:

    • The graphql.schema.json file is generated using the 'introspection' plugin.

    • The graphql.schema.graphql file is generated using the 'schema-ast' plugin.

    • The sdk.ts file is generated using the 'typescript', 'typescript-operations', and 'typescript-generic-sdk' plugins. The documents to be processed are specified in this field. Various configurations for the generated code are also defined here.

The above example are just suggestions, feel free to customize them to your coding style and personal preferences. Also you might find further plugins to be helpful depending on your framework:
https://the-guild.dev/graphql/codegen/plugins

Use in package.json

In combination to run the above configuration code we need all the plugins installed and need to point the commands to the right enviroment and config files.
An example package.json should contain something like this. *(the versions of the packages might differ at the current date)

{
	"scripts": {
		"gen": "graphql-codegen -r dotenv/config --config codegen.ts",
		"gen:watch": "graphql-codegen --watch -r dotenv/config --config codegen.ts"
	},
	"devDependencies": {
		"@graphql-codegen/cli": "^3.3.1",
		"@graphql-codegen/introspection": "3.0.1",
		"@graphql-codegen/typed-document-node": "^4.0.1",
		"@graphql-codegen/typescript": "^3.0.4",
		"@graphql-codegen/typescript-generic-sdk": "^3.1.0",
		"@graphql-codegen/typescript-operations": "^3.0.4"
	}
}

We are using the dotenv package to load the environment variables from the .env file before we start the generation process. This is mandatory since the graphql schema and the whole endpoint is not publicly accessible and always requires an api key, also to fetch the schema.


For a full working sample of this config check one of our starter templates such as

Running the Code Generator

To run the code generator, you can use the npm run gen command. This will regenerate the generated types and SDK.

npm run gen

Additionally, you can use the npm run gen:watch command to watch for changes and regenerate the types and SDK automatically:

npm run gen:watch

These commands should be run from the root of the project.

Conclusion

Using GraphQL Code Generator with caisy can greatly simplify your development process by automatically generating TypeScript types and helper functions from your GraphQL schema. Following the above best practices can help ensure that you use this tool effectively. It's important to remember that the configurations may vary based on your project requirements. Always ensure that your configurations align with your project's needs.

The examples provided in this documentation are not framework-specific, but it's worth noting that the actual implementation might slightly vary depending on the framework and libraries you are using in your project. The principles, however, remain the same across all JavaScript-based frameworks.