graphql-codegen-react-query
Generating types and react-query hooks from a graphql schema.
⚡ Purpose
Graphql codegen is a great tool; zeus-graphql is a neat lib. But they don't exactly fit what I want 😿
🤔 I want to get clean typescript artifacts from my graphql schema
🤔 I want type enforcing for args, params and results while using
useQuery
anduseMutation
hooks🤔 I want to easily import what I need from generated code
🤔 When using a query, I want to pick what I want as result when I only need a subset of the query result
🤔 But I also want to be able to easily pick everything if that's what I need
🤔 I want to define which queries should be translated into infinite queries
So here we go, I just figured I'd do something for giggles 🤷.
⚡ What is generated exactly ?
⚡ Get started
🔶 Install
To install, use either pnpm, yarn or npm:
yarn add -D graphql-codegen-react-query
🔶 Setup
Let's setup our codegen tooling by running the codegen-init
command:
yarn codegen-init
This command takes three optional parameters:
Parameter | Description | Default value |
---|---|---|
c | Where to write the codegen config file | . (current folder) |
o | Where generated code should be written | ./api |
u | Graphql api url. If it doesn't start with http , the variable will be treated as an environment variable name |
http://localhost:3333/graphql |
So if I need to use custom params, I'd do:
yarn gqlCodegen-init -c ./libs/graphql/codegen/src -o libs/graphql/artifacts/src/api -u NEXT_PUBLIC_GQL_API_URL
🗯️ This command generates two files:
- The
react-query.codegen.yml
config file.- The fetcher hook. You might need to inject config in the fetching logic, like setting an
Authorization
header for example; that is why the fetching logic is externalized in this hook.
The config file typically looks like this:
# Where generate code should be written
outputPath: 'libs/graphql/artifacts/src/api/codegen'
# The environment variable name containing the url to the graphql schema (or directly said url)
schemaUrl: NEXT_PUBLIC_GQL_API_URL
# Fetcher hook config
fetcher:
# Path to the fetcher, relative to the generated queries/mutations
path: './../../useFetchData'
# fetcher hook name (expecting a named export)
functionName: 'useFetchData'
# Queries that should be generated as infinite queries with react-query
infiniteQueries:
- useProductsByPage
🔶 Codegen
🚨 Make sure introspection is enabled on the backend you target
Generating types from a graphql schema is easy enough using cli. Usage is as follows:
gqlCodegen -c [configFilePath]
Options:
--help Show help [boolean]
--version Show version number [boolean]
-c Codegen config file path
[required] [default: "./react-query.codegen.yml"]
Examples:
gqlCodegen -c ./libs/graphql/react-query.codegen.yml
With that in mind, we can add a script to our package.json
:
{
[...],
"scripts:" {
"codegen": "gqlCodegen -c ./libs/graphql/react-query.codegen.yml",
[...]
}
}
⚡ Features
🔶 Clean types
From a schema like this...
enum GqlOrderedItemStatus {
preparing
readyToBeSent
shippingInProgress
shipped
}
type GqlOrderedItem {
id: ID!
quantity: Int!
name: String!
image: String
price: Float!
status: GqlOrderedItemStatus!
}
type GqlOrder {
id: ID!
idUser: ID!
idCreditCard: ID!
createdAt: DateTime!
creditCardNumber: String!
items: [GqlOrderedItem!]!
}
I expect to get this:
export type GqlOrderedItemStatus = 'preparing' | 'readyToBeSent' | 'shippingInProgress' | 'shipped'
export interface GqlOrderedItem {
id: string;
quantity: number;
name: string;
image?: string;
price: number;
status: GqlOrderedItemStatus
}
export interface GqlOrder {
id: string;
idUser: string;
idCreditCard: string;
createdAt: Date;
creditCardNumber: string;
items: Array<GqlOrderedItem>;
}
🔶 Dynamic selection and result type inference
It would be great if I could use named query hooks (one react hook by graphql query) but still be able to select what I want in the result 🤔
For example, for a schema like this, I should have a named query hook useCategoriesQuery
with type inference:
type GqlProduct {
id: ID!
idCategory: ID!
name: String!
description: String!
image: String!
price: Float!
stock: Int!
}
type GqlCategoryWithProducts {
id: ID!
name: String!
products: [GqlProduct!]
}
type Query {
categories: [GqlCategoryWithProducts!]!
}
If i want the entire query result, I can use useCategoriesQuery
instead of useCategoriesPartialQuery
:
🔶 Dynamic queries
It would be neat if I could get the results from several graphql queries by calling one single react hook 🤔
Let's use the useGqlQuery
hook that does just that:
🔶 Queries/Mutations variables type support
I would be nice if I had strong typings for arguments and results 🤔
🔶 Queries/Mutations options
It would be awesome if I could still easily tweak react query hooks 🤔