Fullstack, Type safe application with React and GraphQL codegen
Tags: typescript, graphql, tutorial, react
Published: 2022-05-24 09:23:05

There are 2 approaches to defining your schema in GraphQL: schema-first or code-first.

In schema-first, you write `.graphql` (or `.gql`) files, while in code-first you write resolver-like types in Javascript (or Typescript).

<img src="https://blog.escape.tech/content/images/2022/03/image-10.png" />

Now, if you're using Typescript, you might find yourself having to write types again for other purposed, your resolvers for example. That can quickly become a problem, not only because it feels like a waste of time, but also because it makes it that much harder to maintain. If your codebase and your schema grow in complexity, and you have a whole team working on it, a small type definition update can cause a huge mess!

If we look at a fullstack Typescript application, we have to duplicate our type definition at least 3 times:

1. in the schema file
2. in the backend resolvers
3. in the frontend for the GraphQL client
4. BONUS: for the ORM

<img src="https://blog.escape.tech/content/images/2022/03/image-17.png" />

> Enters GraphQL code generator

GraphQL code generator is the solution to that problem: you write your schema file and the rest gets generated automatically!

<img src="https://blog.escape.tech/content/images/size/w1000/2022/03/image-12.png" />

Now let's see how it actually works 👇

_This was originally posted on [blog.escape.tech](https://blog.escape.tech)_

## Example: Building a (over-engineered) blog

I know you love using overly complicated tools to build your blog so let's just do that cause why not 🤷‍♂️

<img src="https://blog.escape.tech/content/images/size/w1000/2022/03/image-13.png" />

Here are the graph relations:

<img src="https://blog.escape.tech/content/images/size/w1000/2022/03/image-14.png" />


As mentioned above, with this stack we would normally have to:

1. write our type definitions in a schema file
2. write types for our backend resolvers
3. write model definitions for our ORM (using Prisma in this example)
4. write types for React Query on the frontend

Phew, that's a lot of effort!

Now imagine if in 4 months we decide to add tags to our posts. We would have to go through the same 4 steps to update the types!

But with GraphQL codegen, we have one single source of truth: the schema file!

Alright, enough teasing, let's jump into the code!

## Backend with Express and Express GraphQL

If you start from scratch, you can simply install Express, Express GraphQL and Typescript (+ some other utilities):
```bash
npm install express express-graphql @graphql-tools/schema cors import-graphql-node
npm install -D @types/express
```

Then we can very easily setup the server:

```ts
import "import-graphql-node"
import express from "express"
import {GraphQLHTTP} from "express-graphql"
import cors from "cors"
import {makeExecutableSchema} from "@graphql-tools/schema"
import * as typeDefs from "./schema.graphql"


const app = express()
app.use(cors())

const schema = makeExecutableSchema({ typeDefs })

app.use("/", GraphQLHTTP({
  context: {db},
  schema: schema,
  graphql: true
}))
```

Note here that I'm using `import-graphql-node` to import `.graphql` files.

[Checkout the repo for more details](https://github.com/AchrafAsh/fullstack-graphql-codegen).

## Frontend with React and React Query

We can bootstrap a React and Typescript project very easily with the Create React App boilerplate:

```bash
npx create-react-app client --template typescript
```

Next, let's add React Query:
```bash
npm install react-query
```

and set it up:
```ts
import "./style.css"
import React from "react"
import ReactDOM from "react-dom"
import App from "./App"
import {QueryClient, QueryClientProvider} from "react-query"

const client = new QueryClient()

ReactDOM.render(
  <React.StrictMode>
    <QueryClientProvider client={client}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>,
  document.getElementById("root")
)
```

## Setting up GraphQL codegen

Setting up GraphQL codegen is super easy! First, install the CLI:

```bash
npm install -D @graphql-codegen/cli
```
Then launch the initialisation proces:
```bash
npx graphql-codegen init
```

This will prompt a series of questions to set it up for your needs. It's not super important as it's very easy to update the configuration later.

<img src="https://blog.escape.tech/content/images/size/w1000/2022/03/image-18.png" />

Here is (approximately) the config file that you'll end up with:

<img src="https://blog.escape.tech/content/images/size/w1000/2022/03/image-19.png" />

Let's go over each field to explain what it does and configure them exactly how we need it.

## Schema

This should point to your schema definition. By default, it uses your GraphQL endpoint, but in general it's easier to put the path to your actual schema file:
```yaml
schema: "server/schema.graphql"
```

## Documents

This is part of the frontend configuration. Documents should point to some schema definition of your operations (queries and mutations). Here's an example:
```graphql
query AllPosts {
  allPosts {
    id
    author {
      displayName
      picture
    }
    title
    publishedAt
    content
    comments {
      id
      text
      username
    }
  }
}
```

```yaml
documents: "client/**/*.graphql"
```

## The React Query Plugin

The installation process didn't gave us an option to add React Query. But we can easily integrate it thanks to the [huge pugin hub](https://www.graphql-code-generator.com/plugins)!:

Fist, we need to install the right plugin:
```bash
npm install -D @graphql-codegen/typescript-react-query
```

Then we configure it in `codegen.yml` configuration file by adding it to the plugins of the frontend section:

```yaml
generates:
  client/src/generated.tsx:
    documents: "client/**/*.graphql" # where the queries are written
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-query"
```

What's amazing about this plugin is that it's also going to take care of configuring the React Query client (endpoint, fetcher, etc) so that we can just use simple hooks, eg. `useGetAllPostsQuery()`

In order to make this work, we need to provide some configuration such as the GraphQL endpoint, but we can also add other things, e.g, an authorization header (with environment variables, how cool is that!):

```yaml
plugins:
    - "typescript"
    - "typescript-operations"
    - "typescript-react-query"
config:
    fetcher:
        endpoint: "process.env.API_URI"
        fetchParams:
            headers:
                Content-Type: "application/json"
                Authorization: "Bearer process.env.HEADER_AUTH_TOKEN"
```

## Putting everything together

We are now ready to go!

To generate the types, we can simply run the command:
```bash
npm run codegen
```

Use the generated types in the backend resolvers:
```ts
import type {QueryAuthorArgs} from "/generated"
import type {Context} from "./context"

const resolvers = {
	Query: {
		author: (
			_parent: null,
			{ id }: QueryAuthorArgs,
			context: Context) => {
			// Do what you got to do to get the author...
		}
	}
	Mutation: {
		createPost: (
      _parent: null,
      { input }: MutationCreatePostArgs,
      ctx: Context
    ) => {
      // Save the post in the database!
    },
	}
}
```

And use the generated hooks in the frontend like so:

```ts
import { useAllPostsQuery } from "./generated";

function App() {
  const { status, error, data } = useAllPostsQuery();
  ...
```

## Conclusion

If you decide to go down the code-first route (blue pill) good for you, but many teams decide to pick a schema-first approach to build their GraphQL API, and even though it's a great option, it can quickly become a burden to [test and maintain your code](https://blog.escape.tech/testing-your-graphql-api/).

But fortunately, graphql-codegen is an elegant solution to fix that problem of code duplication, making the schema file your single source of truth!

## GraphQL Security

[In one of our previous post, we shared how every GraphQL framework has zero security configured by default](https://blog.escape.tech/9-graphql-security-best-practices/). Most GraphQL APIs are therefore subject to the most basic attacks (brute force, DoS, etc).

To compensate this lack of security in the GraphQL ecosystem, we built a quick scan that will get you started im your journey to shipping bullet proof applications!

You can run a dozen security scans on your GraphQL endpoint for free - no signup - at [graphql.security](https://graphql.security)

<img src="https://blog.escape.tech/content/images/2022/03/graphql-security-demo.gif" />