GraphQL Introspection allows fetching the types defined in the target GraphQL API. GraphQL AST allows to navigate through both client-side operations and remote schema types.
In order to generate code and types, GraphQL Code Generator relies on 2 main core concepts of GraphQL:
GraphQL Introspection allows fetching the types defined in the target GraphQL API
GraphQL AST allows to navigate through both client-side operations and remote schema types
Once all GraphQL types (schema types and operations) are identified, GraphQL Code Generator relies on a set of plugins to generate specific code snippets and types.
This process, applied to the @graphql-codegen/typescript plugin, is illustrated below:
Operations and fragments must have unique names
GraphQL Code Generator checks for this automatically and will let you know if you have any conflicts.
Example with @graphql-codegen/typescript
Given the following GraphQL schema:
scalar Date
schema {
query : Query
}
type Query {
me : User !
user ( id : ID ! ): User
allUsers : [ User ]
search ( term : String ! ): [ SearchResult ! ] !
myChats : [ Chat ! ] !
}
enum Role {
USER
ADMIN
}
interface Node {
id : ID !
}
union SearchResult = User | Chat | ChatMessage
type User implements Node {
id : ID !
username : String !
email : String !
role : Role !
}
type Chat implements Node {
id : ID !
users : [ User ! ] !
messages : [ ChatMessage ! ] !
}
type ChatMessage implements Node {
id : ID !
content : String !
time : Date !
user : User !
}
And the following operation (Query) on client-side:
query findUser ( $userId : ID ! ) {
user ( id : $userId ) {
... UserFields
}
}
fragment UserFields on User {
id
username
role
}
And with the following codegen.ts configuration file:
import { CodegenConfig } from '@graphql-codegen/cli' ;
const config : CodegenConfig = {
schema: 'http://localhost:3333' ,
generates: {
'types-and-hooks.tsx' : { plugins: [ 'typescript-operations' , 'typescript-react-query' ] },
},
};
export default config;
@graphql-codegen/typescript plugin can generate the following TypeScript typings and React hooks files based on defined operations:
// …
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID : { input : string ; output : string ; };
String : { input : string ; output : string ; };
Boolean : { input : boolean ; output : boolean ; };
Int : { input : number ; output : number ; };
Float : { input : number ; output : number ; };
Date : { input : any ; output : any ; };
};
export type Query = {
__typename ?: 'Query' ;
me : User ;
user ?: Maybe < User >;
allUsers ?: Maybe < Array < Maybe < User >>>;
search : Array < SearchResult >;
myChats : Array < Chat >;
};
export type QueryUserArgs = {
id : Scalars [ 'ID' ][ 'input' ];
};
export type QuerySearchArgs = {
term : Scalars [ 'String' ][ 'input' ];
};
export enum Role {
User = 'USER' ,
Admin = 'ADMIN'
}
export type Node = {
id : Scalars [ 'ID' ][ 'output' ];
};
export type SearchResult = User | Chat | ChatMessage ;
export type User = Node & {
__typename ?: 'User' ;
id : Scalars [ 'ID' ][ 'output' ];
username : Scalars [ 'String' ][ 'output' ];
email : Scalars [ 'String' ][ 'output' ];
role : Role ;
};
export type Chat = Node & {
__typename ?: 'Chat' ;
id : Scalars [ 'ID' ][ 'output' ];
users : Array < User >;
messages : Array < ChatMessage >;
};
export type ChatMessage = Node & {
__typename ?: 'ChatMessage' ;
id : Scalars [ 'ID' ][ 'output' ];
content : Scalars [ 'String' ][ 'output' ];
time : Scalars [ 'Date' ][ 'output' ];
user : User ;
};
export type FindUserQueryVariables = Exact <{
userId : Scalars [ 'ID' ][ 'input' ];
}>;
export type FindUserQuery = { __typename ?: 'Query' , user ?: { __typename ?: 'User' , id : string , username : string , role : Role } | null | undefined };
export type UserFieldsFragment = { __typename ?: 'User' , id : string , username : string , role : Role };
export const UserFieldsFragmentDoc = `
fragment UserFields on User {
id
username
role
}
` ;
export const FindUserDocument = `
query findUser($userId: ID!) {
user(id: $userId) {
...UserFields
}
}
${ UserFieldsFragmentDoc }` ;
export const useFindUserQuery = <
TData = FindUserQuery ,
TError = unknown
>(
dataSource : { endpoint : string , fetchParams ?: RequestInit },
variables : FindUserQueryVariables ,
options ?: UseQueryOptions < FindUserQuery , TError , TData >
) =>
useQuery < FindUserQuery , TError , TData >(
[ 'findUser' , variables],
fetcher < FindUserQuery , FindUserQueryVariables >(dataSource.endpoint, dataSource.fetchParams || {}, FindUserDocument, variables),
options
);
Now our React components can use the type-safe useFindUserQuery() hook to query the GraphQL API.