Skip to content

Latest commit

 

History

History
203 lines (161 loc) · 4.36 KB

how-does-it-work.mdx

File metadata and controls

203 lines (161 loc) · 4.36 KB

How does GraphQL Code Generator Work?

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:

Codegen flow example

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', '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:

{/* ignore as it's generated code, prettier will remove semicolons /} {/ prettier-ignore */}

// …

/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
  ID: string;
  String: string;
  Boolean: boolean;
  Int: number;
  Float: number;
  Date: 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'];
};


export type QuerySearchArgs = {
  term: Scalars['String'];
};

export enum Role {
  User = 'USER',
  Admin = 'ADMIN'
}

export type Node = {
  id: Scalars['ID'];
};

export type SearchResult = User | Chat | ChatMessage;

export type User = Node & {
  __typename?: 'User';
  id: Scalars['ID'];
  username: Scalars['String'];
  email: Scalars['String'];
  role: Role;
};

export type Chat = Node & {
  __typename?: 'Chat';
  id: Scalars['ID'];
  users: Array<User>;
  messages: Array<ChatMessage>;
};

export type ChatMessage = Node & {
  __typename?: 'ChatMessage';
  id: Scalars['ID'];
  content: Scalars['String'];
  time: Scalars['Date'];
  user: User;
};

export type FindUserQueryVariables = Exact<{
  userId: Scalars['ID'];
}>;


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.