DEV Community

Pascal Martineau
Pascal Martineau

Posted on • Updated on

End to end type safety

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 (who are also responsible for GraphQL Helix) have put together a powerful tool called GraphQL Code Generator to do exactly that.

Setting up GraphQL Code Generator

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

yarn add -D @graphql-codegen/cli @graphql-codegen/typescript
Enter fullscreen mode Exit fullscreen mode

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

schema: generated/schema.graphql
generates:
  generated/schema.ts:
    plugins:
      - typescript
Enter fullscreen mode Exit fullscreen mode

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:

"codegen": "NODE_NO_WARNINGS=1 graphql-codegen",
Enter fullscreen mode Exit fullscreen mode

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:

yarn add -D @urql/vue @graphql-codegen/near-operation-file-preset @graphql-codegen/typescript-operations @graphql-codegen/typescript-vue-urql
Enter fullscreen mode Exit fullscreen mode

Then we need to configure documents and add an entry under generates for our desired output inside codegen.yml:

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
Enter fullscreen mode Exit fullscreen mode

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.

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

query Hello {
  hello
}
Enter fullscreen mode Exit fullscreen mode

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:

hooks:
  afterAllFileWrite:
    - eslint --fix ./generated ./composables
Enter fullscreen mode Exit fullscreen mode

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:

build: {
  transpile: ["@urql/vue"],
},
typescript: { strict: true },
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)