Effortless GraphQL in Next.js: Elevate Your DX with Codegen and more
Tags: graphql, nextjs, typescript, webdev
Published: 2024-06-25 22:02:25

## Introduction

GraphQL endpoints are gaining popularity for their flexibility, efficient data fetching, and strongly typed schema. Putting these powers in hands of API consumers will elevate the Developer Experience (DX) and leads to building robust and maintainable applications. Combining Next.js, GraphQL, and TypeScript offers a powerful stack that can significantly improve your productivity and code quality.

In this article, I will walk you through setting up a Next.js project that uses Hasura for an instant GraphQL endpoint. We will demonstrate how to achieve code auto-completion and type hinting in VSCode using a  few tools and extensions and one of GraphQL's superpowers - introspection. By the end of this guide, you'll have a seamless development setup that boosts your efficiency and code accuracy.

## Outline

In this article we will walk through the following steps:

- Creating a sample GraphQL endpoint, we will use Hasura Cloud.
- Installing prerequisites and creating a fresh Next.js app.
- Minimal wiring of a GraphQL endpoint in our Next.js app.
- Installing extensions and tools for GraphQL IntelliSense in VS Code.
- Setting up tools for typed variables and responses in `useQuery` hook.
- Enhancing `npm run dev` to concurrently run all the required tools.

## Setting Up Hasura

Visit [Hasura Cloud](https://cloud.hasura.io/) and create an account. Click "New Project" in the projects tab. 

![Hasura Cloud's New project settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r883ulu4tmami24sigqa.png)

Select desired options and proceed. Your project will be created instantly, click "Launch Console". Switch to the "DATA" tab and click "Connect Neon Database". Neon is essentially a Postgres database on a serverless platform, you can read more on the [Neon's website](https://neon.tech/).

![Click "Connect Neon Database"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cpis51h26oqgs027gls.png)



Wait a while and click "default" database in the sidebar. Click the first template, "👋 Welcome to Hasura!" in the "Template Gallery" page, then click "Install Template".

![Click "default" in the sidebar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h4bykctd6qir29y0780y.png)

We are almost done, just head to the "API" tab and copy both GrphQL endpoint URL, and the string in front of `x-hasura-admin-secret` request header. To manage our Hasura endpoint URL and admin secret, we'll use environment variables.

## Setting Up Prerequisites and creating a fresh Next.js Project 

Ensure you have the following:

- Basic understanding of Next.js and GraphQL.
- Node.js and npm/yarn installed.
- Visual Studio Code installed.
- A running Hasura instance (I'll use Hasura Cloud's free tier).

Now, let's create a new Next.js project. We will install the necessary dependencies in the next steps. Initialize a New Project:

```
npx create-next-app@latest my-graphql-app # Proceed with default choices
code my-graphql-app # Open the project in Visual Studio Code 
```

## Configuring for Minimal GraphQL Endpoint Access

Switch to VS Code, create a blank file, `.env.local`, this is Next.js's default file for storing dev environment variables. Add your Hasura Cloud's endpoint URL and the `x-hasura-admin-secret` value: 

```
NEXT_PUBLIC_GQL_URL="https://charmed-finch.hasura.app/v1/graphql/"
NEXT_PUBLIC_HASURA_ADMIN_SECRET="FHU82EdNTGfMSExUkip4TUtLtLM1T..."
```

Note that environment variables prefixed with `NEXT_PUBLIC_` are exposed to the client-side. I'm using Hasura admin secret for the sake of simplicity, and you should use a proper authentication method for your real project, see [Hasura's Authentication and Authorization](https://hasura.io/docs/latest/auth/overview/) for more info.

We will `urql` a rather minimal GraphQL client:

```bash
npm i urql
```

Open `app/page.tsx` and replace the default content with this minimal query:

```tsx
"use client"
import { Client, Provider, cacheExchange, fetchExchange, gql, useQuery } from "urql";

const Customer = () => {
  const CUSTOMERS_QUERY = gql`
    query CustomersQuery {
      customer { first_name }
    }
  `;
  const [{ data }] = useQuery({
    query: CUSTOMERS_QUERY,
  });
  return JSON.stringify(data);
}

const client = new Client({
  url: process.env.NEXT_PUBLIC_GQL_URL ?? '',
  exchanges: [cacheExchange, fetchExchange],
  fetchOptions: {
    headers: {
      "x-hasura-admin-secret": process.env.NEXT_PUBLIC_HASURA_ADMIN_SECRET ?? ''
    }
  },
});

export default function Home() {
  return <Provider value={client}>
    <Customer />
  </Provider>;
}
```

Check your app in a browser, you should see the raw data.


# Setting Up Visual Studio Code for GraphQL IntelliSense 

- Install [GraphQL: Language Feature Support](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql) VS Code extension

- The installed extension expects a GraphQL schema file, so we will use `graphqurl` to introspect the GraphQL endpoint and download the full schema into a `schema.graphql` file. We will also use `dotenv-cli` package to pass variables from the `.env.local` file to the `graphqurl` command.

- Install required packages:

```
npm i -D graphqurl dotenv-cli
```

- And add to your `package.json` scripts:

```
"dev:introspect": "dotenv -e .env.local -- npm run dev:_introspect",
"dev:_introspect": "gq %NEXT_PUBLIC_GQL_URL% -H \"X-Hasura-Admin-Secret: %NEXT_PUBLIC_HASURA_ADMIN_SECRET%\" --introspect > schema.graphql",
```

- Run `npm run dev:introspect` and wait for the `schema.graphql` file to be generated in the project's root directory.

- Create a blank file `graphql.config.ts` with the following content to hint the extension on where the schema file is and in which files the IntelliSense should work:

```ts
export default {
    schema: './schema.graphql',
    documents: ['**/*.{graphql,js,ts,jsx,tsx}'],
};
```

- Restart VS Code and test IntelliSense by editing the query:

![GraphQL IntelliSense demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/42d5fuoou3jcd72hgsaz.gif)

## Setting Up Codegen for Typed Query Variables and Responses

- Install dependencies:

```
npm install -D @graphql-codegen/cli @parcel/watcher
```

- Add `codegen.ts` file to the project's root directory:

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

const config: CodegenConfig = {
  schema: {
    [process.env.NEXT_PUBLIC_GQL_URL?? '']: {
      headers: {
        "x-hasura-admin-secret": process.env.NEXT_PUBLIC_HASURA_ADMIN_SECRET ?? '',
      },
    },
  },
  documents: ['**/*.{ts,tsx}'],
  generates: {
    './__generated__/': {
      preset: 'client',
    }
  },
  ignoreNoDocuments: true,
};

export default config;
```

- Add to your `package.json` scripts:

```
"dev:codegen": "graphql-codegen --require dotenv/config --config codegen.ts dotenv_config_path=.env.local --watch",
```

- Use generated `graphql` function instead of `urql`'s `gql` literal:

```ts
import { graphql } from '../__generated__/gql'

const CUSTOMERS_QUERY = graphql(`
  query CustomersQuery {
    customer { first_name }
  }
`);
```

- Great, now run `npm run dev:codegen`, edit the query, save the file, and wait a moment for the codegen to re-generate the type files. Enjoy typed variables and query responses.


![GraphQL typed variables and responses](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfif4lznhzqyw9tntfkm.gif)

## Running Everything Together

We'll use [`concurrently`](https://www.npmjs.com/package/concurrently) to run the introspection, codegen, and Next.js dev server all together.

- Install Dev Dependencies:

```
npm install -D concurrently
```

- Rename the original `dev` script and add concurrently script to `package.json` as the new `dev` script:

```
"dev:next": "next dev",
"dev": "concurrently 'npm:dev:next' 'npm:dev:codegen' 'npm:dev:introspect'",
```

- Run the dev server as before:

```
npm run dev
```

## Benefits of Enhanced DX

By following these steps, you achieve the following benefits:

- Code Auto-completion: Automatically suggests GraphQL queries and schema details as you type, reducing the need for constant reference checks.

- Type Safety: Ensures that your GraphQL queries and mutations are type-safe, reducing runtime errors and improving maintainability.

- Reduced Errors: With auto-completion and type hinting, the likelihood of making syntax or schema-related errors decreases significantly.

## Conclusion

In this guide, we've shown you how to set up a Next.js project with GraphQL using urql, configure your environment for optimal DX with Hasura, and leverage TypeScript and VSCode tools to improve your coding experience. By integrating these technologies, you can streamline your development workflow, reduce errors, and build more robust applications.

By adopting these practices, you'll enhance your development workflow and enjoy a more productive and efficient coding experience. Happy coding!