Automatically generate Typescript types for your GraphQL schema
Tags: typescript, graphql, javascript, node
Published: 2021-10-30 10:27:50

---
title: Automatically generate Typescript types for your GraphQL schema
published: true
description: 
tags: typescript, graphql, javascript, nodejs
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5w5i8wbut1tacsug1dez.png
---

## Introduction

In this post, I will show you how to automatically generate types for your GraphQL APIs written in Typescript using [GraphQL codegen](https://www.graphql-code-generator.com/).

## Prerequisites

Some GraphQL and Typescript knowledge is expected. NodeJS and Typescript must be installed on your machine.

## Context

#### Typescript

[Typescript](https://www.typescriptlang.org/) is a static type checker for JavaScript. It is used as a development tool and helps writing better code and catching potential errors while developing instead that on runtime.

#### GraphQL

[GraphQL](https://graphql.org/) is a query language for writing HTTP APIs. It is very flexible and can help optimizing network load as well as the number of endpoints that you would need in a typical REST API.

#### Apollo GraphQL

[Apollo GraphQL](https://www.apollographql.com/) is a framework/toolset for building GraphQL APIs. It provides solutions both for server and client.

#### GraphQL code generator (graphql-codegen)

[graphql-codegen](https://www.graphql-code-generator.com/) is a tool that automatically generates Typescript types from GraphQL types and resolvers definition.

## What are we going to build

We will build a simple GraphQL API that will manage painters and it's paintings. We'll use Apollo server and graphql-codegen for generating the Typescript types automatically, which will be available to use across the codebase.

If you feel lost at any point or simply want to speed up things, here you can find the final code: https://github.com/xcanchal/apollo-server-typescript

## Hands-on

First of all, create a new folder for the project and initialize the npm project:

```shell
$ mkdir {project-name}
$ cd {project-name}
$ npm init --yes
```

Install the following dependencies and devDependencies:

```shell
$ npm install --save apollo-server graphql

$ npm install --save-dev typescript @tsconfig/recommended graphql-codegen @graphql-codegen/cli @graphql-codegen/typescript nodemon ts-node
```

Create the [tsconfig.json](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html), the configuration file for Typescript . We'll use the recommended example but we'll add an extra property `outDir`, because we want the generated files to be put all  inside the 'dist/' folder instead of next to each original `.ts` file:

```json
{
  "compilerOptions": {
    "outDir": "dist",
    "target": "ES2015",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Recommended"
}
```

To finish with the basic initial setup, add the following `dev` command under the `package.json` scripts. This command will be used for running the server in development mode (building the JS files and restarting it on every change):

```json
"scripts": {
  "dev": "nodemon --exec ts-node ./server.ts --watch"
}
```

Now, let's write the code for our GraphQL server. Create a new `server.ts` file and ignore editor errors, if any, for now:

```ts
import { ApolloServer } from 'apollo-server';

import typeDefs from './type-defs';
import resolvers from './resolvers';

(async () => {
  const server = new ApolloServer({ typeDefs, resolvers });
  const { url } = await server.listen();
  console.log(`🚀 Server ready at ${url}`);
})();
```

We will use a couple of arrays to work as a database. Create a new file named `database.ts` and paste the following content. Temporarily, we will use `any` for the entities types (don't judge me, we'll fix that later!)

```ts
export const painters: any[] = [];
export const paintings: any[] = [];
```

Great! so now we can start defining the schema for our API. Create a new file named `type-defs.ts` and add the types for the `Painter` and `Painting` entities:

```typescript
import { gql } from 'apollo-server';

export default gql`
  type Painter {
    name: String!
    country: String!
    techniques: [String]!
  }

  type Painting {
    author: String!
    title: String!
    technique: String!
    date: String!
  }
`
```

We need a way to insert new painters and paintings into our database. Let's define our first mutation in the `type-defs.ts` file, which will allow us to create painters:

```graphql
# [...]

input PainterInput {
  name: String!
  country: String!
  techniques: [String]!
}

type Mutation {
  createPainter(input: PainterInput!): Painter!
}
```

After that, let's add a similar mutation for creating paintings:

```graphql
# [...]

input PaintingInput {
  author: String!
  title: String!
  technique: String!
  date: String!
}

type Mutation {
  # [...]
  createPainting(input: PaintingInput!): Painting!
}
```

The next step will be creating the resolvers, which will tell GraphQL how to query or mutate the data associated with the previously defined types. 

Create a file named `resolvers.ts` with the following content (again, we'll use `any` until we generate the typescript types):

```typescript
import { painters, paintings } from './database';

const resolvers = {
  Mutation: {
    createPainter(_: any, { input: painter }: any): any {
      painters.push(painter);
      return painter;
    },
    createPainting(_: any, { input: painting }: any): any {
      paintings.push(painting);
      return painting;
    }
  }
};

export default resolvers;
```

Up to this point, we can insert painters and paintings. The next step is to implement a few queries to retrieve the data from the database. Add the following queries to the `type-defs.ts` file.

```graphql
# [...]

type Query {
  painters: [Painter]! # get all painters
  paintings: [Painting]! # get all paintings
  painter(name: String): Painter # get a painter by name
  painting(title: String): Painting # get a painting by title
}
```

And also add the respective resolvers to the `resolvers.ts` file.

```typescript
// [...]

const resolvers = {
  // [...]
  Query: {
    painters: (): any => painters,
    paintings: (): any => paintings,
    painter(_: any, { name }: any): any {
      console.log(name);
      return painters.find((painter) => painter.name === name);
    },
    painting(_: any, { title }: any): any {
      return paintings.find((painting) => painting.title === title);
    },
  },
// [...]
};
```

Your `type-defs.ts` file should look like this:

```typescript
import { gql } from 'apollo-server';

export default gql`
  type Painter {
    name: String!
    country: String!
    techniques: [String]!
  }

  type Painting {
    author: String!
    title: String!
    technique: String!
    date: String!
  }

  input PainterInput {
    name: String!
    country: String!
    techniques: [String]!
  }

  input PaintingInput {
    author: String!
    title: String!
    technique: String!
    date: String!
  }

  type Query {
    painters: [Painter]!
    paintings: [Painting]!
    painter(name: String): Painter
    painting(title: String): Painting
  }

  type Mutation {
    createPainter(input: PainterInput!): Painter!
    createPainting(input: PaintingInput!): Painting!
  }
`
```

And the `resolvers.ts` file should look like:

```typescript
import { painters, paintings } from './database';

const resolvers = {
  Query: {
    painters: (): any => painters,
    paintings: (): any => paintings,
    painter(_: any, { name }: any): any {
      console.log(name);
      return painters.find((painter) => painter.name === name);
    },
    painting(_: any, { title }: any): any {
      return paintings.find((painting) => painting.title === title);
    },
    },
  },
  Mutation: {
    createPainter(_: any, { input: painter }: any): any {
      painters.push(painter);
      return painter;
    },
    createPainting(_: any, { input: painting }: any): any {
      paintings.push(painting);
      return painting;
    }
  }
};

export default resolvers;
```

Now that we have defined defining the types and resolvers for our API, let's run the server in development mode and see how it looks inside Apollo Studio, which is a playground for testing it. 

Execute `npm run dev`, open a new browser navigate to it:

```shell
$ npm run dev

// -> 🚀 Server ready at http://localhost:4000/
```

After clicking on the "Query your server" button you'll land at the Apollo Studio, where you'll be able to explore the schema definition as well as trying to execute the mutations and queries that we have implemented.

![Apollo Studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i1ion4qgn5k4hli9asur.png)

The last thing to do, and the cherry on top of this article, is to generate the Types to be used in our typescript files that match our GraphQL schema.

Let's return to the codebase to configure `graphql-codegen`. Create a new file named `codegen.yaml` and paste the following basic configuration (see the complete list of available options [here](https://www.graphql-code-generator.com/docs/getting-started/codegen-config)):

```yaml
schema: "./type-defs.ts" # GraphQL types (input file)
generates:
  ./gql-types.d.ts: # Typescript types (output generated file)
    plugins: # List of needed plugins (installed as devDeps)
      - typescript
```

Finally, add a new script in the `package.json` for convenience:

```json
"scripts": {
  "generate-gql-types": "graphql-codegen"
}
```

Execute it (`npm run generate-gql-types`) and see how a new file with the name we defined in the `codegen.yaml`(`gql-types.d.ts`) gets generated. This file contains all the Typescript types:

```typescript
export type Maybe<T> = T | null;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
  ID: string;
  String: string;
  Boolean: boolean;
  Int: number;
  Float: number;
};

export type Mutation = {
  __typename?: 'Mutation';
  createPainter: Painter;
  createPainting: Painting;
};


export type MutationCreatePainterArgs = {
  input: PainterInput;
};


export type MutationCreatePaintingArgs = {
  input: PaintingInput;
};

export type Painter = {
  __typename?: 'Painter';
  country: Scalars['String'];
  name: Scalars['String'];
  techniques: Array<Maybe<Scalars['String']>>;
};

export type PainterInput = {
  country: Scalars['String'];
  name: Scalars['String'];
  techniques: Array<Maybe<Scalars['String']>>;
};

export type Painting = {
  __typename?: 'Painting';
  author: Scalars['String'];
  date: Scalars['String'];
  technique: Scalars['String'];
  title: Scalars['String'];
};

export type PaintingInput = {
  author: Scalars['String'];
  date: Scalars['String'];
  technique: Scalars['String'];
  title: Scalars['String'];
};

export type Query = {
  __typename?: 'Query';
  painter?: Maybe<Painter>;
  painters: Array<Maybe<Painter>>;
  painting?: Maybe<Painting>;
  paintings: Array<Maybe<Painting>>;
};


export type QueryPainterArgs = {
  name?: Maybe<Scalars['String']>;
};


export type QueryPaintingArgs = {
  title?: Maybe<Scalars['String']>;
};
```

Pretty cool, right? Then you'll love it when you see how they looks when we actually use them in the code and we really benefit from the type checking:

First of all, let's update the `database.ts` file:

```typescript
import { Painter, Painting } from './gql-types';

export const painters: Painter[] = [];
export const paintings: Painting[] =[];
```

After that, do the same in the `resolvers.ts` file:

```typescript
import { painters, paintings } from './database';
import {
  Painter,
  Painting,
  MutationCreatePainterArgs,
  MutationCreatePaintingArgs,
  QueryPainterArgs,
  QueryPaintingArgs,
} from './gql-types';

const resolvers = {
  Query: {
    painters: (): Painter[] => painters,
    paintings: (): Painting[] => paintings,
    painter(_: any, { name }: QueryPainterArgs): Painter | undefined {
      console.log(name);
      return painters.find((painter) => painter.name === name);
    },
    painting(_: any, { title }: QueryPaintingArgs): Painting | undefined {
      return paintings.find((painting) => painting.title === title);
    },
  },
  Mutation: {
    createPainter(_: any, { input: painter }: MutationCreatePainterArgs): Painter {
      painters.push(painter);
      return painter;
    },
    createPainting(_: any, { input: painting }: MutationCreatePaintingArgs): Painting {
      paintings.push(painting);
      return painting;
    }
  }
};

export default resolvers;
```

## Conclusion

Awesome! you have completed this tutorial. By following this approach, there's no need to define the same entities twice (one for GraphQL and one for Typescript) and we can focus on what really matters when designing, implementing and maintaining a GraphQL API: its schema types, queries, and mutations. 

With `graphql-codegen`, we get the Typescript types automatically generated and our code is consistent with the GraphQL schema without much effort, apart from any configuration tweaks that may be needed as the application evolves.

**This is one of many ways to work with Typescript and GraphQL, so if you follow a different approach, don't doubt to share it so we can learn something new!**

--- 

Follow me on Twitter for more content [@xcanchal](https://twitter.com/xcanchal)

Buy me a coffee:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3ki0c6ebma5xea1x4qm.png)