Introduction to GraphQL Code Generator#
GraphQL Code Generator is a plugin-based tool that helps you get the best out of your GraphQL stack.
From back-end to front-end, GraphQL Code Generator automates the generation of:
- Typed Queries, Mutations and, Subscriptions for React, Vue, Angular, Next.js, Svelte, whether you are using Apollo Client, URQL or, React Query.
- Typed GraphQL resolvers, for any Node.js (GraphQL Yoga, GraphQL Modules, TypeGraphQL or Apollo) or Java GraphQL server.
- Fully-typed Node.js SDKs, Apollo Android support, and more!
The perfect GraphQL Developer Experience#
To illustrate how GraphQL Code Generator improves your developer experience, let's take a look at the front-end and back-end usage of the following schema:
# schema.graphql
type Author {
id: Int!
firstName: String!
lastName: String!
posts(findTitle: String): [Post]
}
type Post {
id: Int!
title: String!
author: Author
}
type Query {
posts: [Post]
}
The following sections showcase why GraphQL Code Generator is a game-changer for your GraphQL Stack.
From the front-end#
Most client-side implementations without GraphQL Code Generator would query the API as showcased in the following examples:
import { useQuery } from 'urql'
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = /* GraphQL */ `
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const [result] = useQuery<PostQuery>({ query: postsQueryDocument })
// ...
}
import { request, gql } from 'graphql-request'
import { useQuery } from 'react-query'
interface PostQuery {
posts: {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}[]
}
const postsQueryDocument = gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const Posts = () => {
const { data } = useQuery<PostQuery>('posts', async () => {
const { posts } = await request(endpoint, postsQueryDocument)
return posts
})
// ...
}
<template>
<div class="apollo">
<!-- UI... -->
</div>
</template>
<script lang="ts">
interface PostQueryVariables {
id: string
}
export default {
apollo: {
post: {
query: gql`
query ($id: ID!) {
post(id: $id) {
id
title
author {
id
firstName
lastName
}
}
}
`,
variables: {
id: 1
} as PostQueryVariables
}
},
data() {
return {
post: undefined
}
}
}
</script>
const GET_POSTS = gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
interface Post {
id: string
title: string
author?: {
id: string
firstName: string
lastName: string
}
}
@Component({
/* ... */
})
class PostsComponent implements OnInit, OnDestroy {
posts: Post[]
private querySubscription: Subscription
ngOnInit() {
this.querySubscription = this.apollo
.watchQuery({
query: GET_POSTS
})
.valueChanges.subscribe(({ data }) => {
this.posts = data.posts as Post[]
})
}
ngOnDestroy() {
this.querySubscription.unsubscribe()
}
}
<script lang="ts">
import { query } from 'svelte-apollo'
const postsQueryDocument = gql`
query Posts {
posts {
id
title
author {
id
firstName
lastName
}
}
}
`
const posts = query(postsQueryDocument)
</script>
<ul>
<!-- UI -->
</ul>
Manually maintaining the GraphQL operation types or the complete absence of types can lead to many issues:
-
outdated typing (regarding the current Schema)
-
typos
-
partial typing of data (not all Schema's fields has a corresponding type)
The strength of your front-end application types is based on your data types. Any mistake on your manually maintained data types ripples in many of your components.
For this reason, automating and generating the typing of your GraphQL operations will both improve the developer experience and stability of your stack.
After installing and configuring GraphQL Code Generator, our front-end code will be fully-typed and up-to-date as follows:
import { useQuery } from 'urql'
import { postsQueryDocument } from './graphql/generated'
const Posts = () => {
const [result] = useQuery({ query: postsQueryDocument })
// `result` is fully typed!
// ...
}
import { usePosts } from '../graphql/generated'
const Posts = () => {
const { data } = usePosts()
// `data` is typed!
// ...
}
<template>
<div class="apollo">
<!-- UI... -->
</div>
</template>
<script>
import { usePostQuery } from '../generated/graphql'
export default {
apollo: usePostQuery({
// `variables` is properly typed!
variables: {
id: 1
}
}),
data() {
return {
post: undefined
}
}
}
</script>
import { PostsGQL, PostsQuery } from './graphql'
//BE SURE TO USE Observable from `rxjs` and not from `@apollo/client/core` when using map
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
@Component({
/* ... */
})
export class PostsComponent {
posts: Observable<PostsQuery['posts']>
constructor(postsGQL: PostsGQL) {
this.posts = postsGQL.watch().valueChanges.pipe(map(result => result.data.posts))
}
}
<script lang="ts">
import { Posts } from '../graphql/generated'
// `posts` is fully typed, also are `Posts()` options!
const posts = Posts()
</script>
<ul>
<!-- UI -->
</ul>
Now, with simple configuration and an npm/yarn script, a front-end developers benefits from:
-
up-to-date typings
-
autocompletion on all queries, mutations and, subscription variables and results
-
less boilerplate (thanks to full code generation such as React hooks generation)
How does GraphQL Code Generator work?
More details on the inner working of GraphQL Code Generator are available on this page.
To the back-end#
Most GraphQL API resolvers remain untyped or wrongly typed which, leads to multiple issues:
-
resolvers are not compliant with the schema definition
-
typos in the resolvers' function type signature
For this reason, GraphQL Code Generator provides multiple plugins that help you automate the generation of resolvers' typings.
Here are an example of a GraphQL API leveraging GraphQL Code Generator resolvers typings (based on the schema.graphql
above):
import { ApolloServer } from 'apollo-server'
import { readFileSync } from 'fs'
import { Resolvers } from './resolvers-types'
const typeDefs = readFileSync('./schema.graphql', 'utf8')
const resolvers: Resolvers = {
Query: {
// typed resolvers!
}
}
const server = new ApolloServer({ typeDefs, resolvers })
// The `listen` method launches a web server.
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
import { createServer } from '@graphql-yoga/node'
import { readFileSync } from 'fs'
import { Resolvers } from './resolvers-types'
const typeDefs = readFileSync('./schema.graphql', 'utf8')
const resolvers: Resolvers = {
Query: {
// typed resolvers!
}
}
const server = createServer({
typeDefs,
resolvers
})
server.start()
Given the following structure:
- src/
- modules/
- user/
- resolvers.ts
- typedefs/
- user.graphql
- product/
- resolvers.ts
- typedefs/
- product.graphql
The User module resolvers would be:
// src/modules/user/resolvers.ts
import { UsersModule } from './generated-types/module-types'
export const resolvers: UsersModule.Resolvers = {
// Here, you can implement only the types and fields defined in your module!
}
What's next?#
Start by installing GraphQL Code Generator in your project.
Then, you can either read a guide or go over the list of available plugins to find more plugins that satisfy your needs.
If you are experiencing any issues, you can reach us via the following channels:
- Found a bug? report it in our GitHub repo
- Need help or have a question? You can use the live chat box in the corner of the screen, ask it in our GitHub Discussions page or reach out to us directly in our Discord
- We have more awesome open source tools!
- You can visit our website for more information about us and what we do