End to end type safety
Tags: graphql, typescript, nuxt3
Published: 2022-02-23 13:48:41

One of the best things about GraphQL and TypeScript is the prospect of end to end type safety, i.e. having strict type checking and auto-completion from the back end all the way to the front end. This makes for a great DX and can potentially prevent errors as well.

In order to achieve this, our project can leverage code generation to alleviate the tedious process of manually creating the typings for our GraphQL schema and operations. The fine people at [The Guild](https://www.the-guild.dev/) (who are also responsible for GraphQL Helix) have put together a powerful tool called [GraphQL Code Generator](https://www.graphql-code-generator.com/) to do exactly that.

## Setting up GraphQL Code Generator

First of all, we'll add the required packages:

```shell
yarn add -D @graphql-codegen/cli @graphql-codegen/typescript
```

We'll need a `codegen.yml` configuration file at the root of our project. A simple configuration looks like this:

```yaml
schema: generated/schema.graphql
generates:
  generated/schema.ts:
    plugins:
      - typescript
```

We could use `http://localhost:3000/api/graphql` instead of `generated/schema.graphql` to enable executing our operations directly from VS Code but this requires having the development server constantly running in the background (the code generation would also fail otherwise).

Let's add a `codegen` script to our `package.json` for running the code generation:
```json
"codegen": "NODE_NO_WARNINGS=1 graphql-codegen",
```

_The annoying `ExperimentalWarning: stream/web is an experimental feature.` can be hidden by adding `NODE_NO_WARNINGS=1` in front of the `codegen` script in `package.json`._

We can now generate the typings with `yarn codegen` or watch for changes with `yarn codegen -w`.

## Generating type safe GraphQL operations

Now that we have generated the schema types, it's time to generate typings for our GraphQL operations as well (queries, mutations and subscriptions). For this purpose, the choice of generator plugins will depend on the GraphQL client we plan on using, in our case `@urql/vue` (see the next article of the series for details).

Let's add `@urql/vue` and the required `graphql-codegen` plugins:

```shell
yarn add -D @urql/vue @graphql-codegen/near-operation-file-preset @graphql-codegen/typescript-operations @graphql-codegen/typescript-vue-urql
```

Then we need to configure `documents` and add an entry under `generates` for our desired output inside `codegen.yml`:
```yaml
schema: generated/schema.graphql
documents: graphql/**/*.graphql
generates:
  generated/schema.ts:
    plugins:
      - typescript
  composables/:
    preset: near-operation-file
    presetConfig:
      baseTypesPath: ../generated/schema.ts
      extension: .ts
      folder: ../composables
    config:
      documentMode: documentNode
    plugins:
      - typescript
      - typescript-operations
      - typescript-vue-urql
```

As you can see, our source documents will live in `.graphql` files under the `graphql/` directory and the type safe operations will be generated in `composables/*.ts`. By using `@graphql-codegen/near-operation-file-preset`, we can generate one file per operation and thus benefit from the auto importing feature of Nuxt3 (again, see the next article of this series).

For more information on the options above, please refer to the various `graphql-codegen` plugins' [documentation](https://www.graphql-code-generator.com/plugins).

Before code generating again, we'll need to create at least one operation file, so let's add `graphql/hello.query.graphql`:
```graphql
query Hello {
  hello
}
```

It's important to name your operations inside each document file since the generated composables will be named accordingly, i.e. `query Hello` becomes `useHelloQuery`.

We can also make sure the generated code will be properly formatted by adding a command to the `afterAllFileWrite` hook in `codegen.yml`:
```yaml
hooks:
  afterAllFileWrite:
    - eslint --fix ./generated ./composables
```

Finally, there are some options that are needed in `nuxt.config.ts` to prevent runtime errors with `@urql/vue` and to enable strict type-checking:
```typescript
build: {
  transpile: ["@urql/vue"],
},
typescript: { strict: true },
```

We're now ready to start using our type safe operations on the front end!