npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

apollo-hooks-codegen

v1.2.0

Published

A plugin for graphql-code-generator to create fully typed React Hooks from GraphQL queries, mutations and subscriptions.

Readme

This is a plugin for graphql-code-generator that generates fully typed React Hooks from queries, mutations and subscriptions in .graphql files.

Getting started

Installation

npm i -D graphql-code-generator apollo-hooks-codegen

Writing Queries

Unless traditional Apollo usage, we're actually writing all our queries, mutations and subscriptions inside a dedicated .graphql file:

# /src/graphql/todos.graphql
fragment TodoParts on TodoItem {
  id
  title
  isDone
}

query getAllTodos {
  todoItems {
    ...TodoParts
  }
}

subscription subscribeTodos {
  newTodoItem: subscribeTodoItems {
    ...TodoParts
  }
}

mutation createTodo($todoItem: TodoItemInput!) {
  createTodoItem(todoItem: $todoItem) {
    id
  }
}

Setting up codegen

The graphql-code-generator is best configured via a codegen.yml file.

Here we tell the generator to create a ./src/graphql/index.ts file using apollo-hooks-codegen.

# codegen.yml
schema: http://localhost:4000
documents: ./src/graphql/*.graphql
overwrite: true
generates:
  ./src/graphql/index.ts:
    - apollo-hooks-codegen

After creating the file, we just run: npx gql-gen

Configuring ApolloClient

The hooks need access to an instance of ApolloClient. If you previously used Apollo, you probably already have this set up, otherwise, refer to the Get started guide.

The code generator created an ApolloHooksProvider, which we have to set up at the root of our app:

import { ApolloHooksProvider } from './src/graphql'

const apolloClient = new ApolloClient({
  /* ApolloClient configuration here */
})

function AppWithApollo() {
  return (
    <ApolloHooksProvider apolloClient={apolloClient}>
      <App />
    </ApolloHooksProvider>
  )
}

After all of this is done, we can now start using the generated hooks.

Usage

Every document (query, mutation, subscription or fragment) in the .graphql file generated a Typescript function of the same name.

Each function takes an optional argument, which contains additional options. The configured document is then passed to one of the provided hooks:

Queries

useQuery uses watchQuery under the hood, so the component will re-render automatically if the queried data changes in Apollo's cache for any reason.

import { useQuery, getAllTodos } from './src/graphql'

function TodoList() {
  const queryResult = useQuery(getAllTodos({ fetchPolicy: 'cache-first' }))

  // get access to loading and error state of the query
  if (queryResult.loading) return <p>Loading...</p>
  if (queryResult.error) return <p>Error</p>

  // data is null during loading and in case of error, but can be expected to be non-null otherwise
  const todoItems = queryResult.data!.todoItems

  // the compiler knows about which fields are available on todoItems
  return (
    <ul>
      {todoItems.map(item => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  )
}

Mutations

useMutation creates a function which executes the configured mutation and returns the result as a Promise.

import { useMutation, createTodo } from './src/graphql'

function AddTodoButton() {
  const mutate = useMutation(
    createTodo({
      // options can be passed directly during configuration, like with useQuery.
      // alternatively, you can pass the options object later when calling the mutate function
      variables: {
        todoItem: { title: 'Finish this button component...' },
      },
    })
  )

  return (
    <button
      onClick={() => {
        mutate().then(console.log)
      }}
    >
      Click me!
    </button>
  )
}

Subscriptions

Subscriptions require additional work when setting up ApolloClient, see here.

import { useSubscription, subscribeTodos } from './src/graphql'

function TodoItemTicker() {
  const sub = useSubscription(subscribeTodos())

  // If we did not receive a subscription event yet, the value is null
  if (sub == null) return null

  return <p>Latest Todo: {sub.newTodoItem.title}</p>
}

Often, you want to send a query to get some data, and create a subscription to be called back whenever the data changes on server. You can use this helper function to do both in one:

import { useQuery, getAllTodos } from './src/graphql'

function TodoList() {
  const queryResult = useQueryWithSubscription(
    getAllTodos(), // the initial query
    subscribeTodos(), // the subscription
    (queryData, subData) => ({
      // Update the query data here with the latest data from the subscription
      todoItems: [...queryData.todoItems, subData.newTodoItem],
    })
  )

  // loading and error state are taken only from the query
  if (queryResult.loading) return <p>Loading...</p>
  if (queryResult.error) return <p>Error</p>

  const todoItems = queryResult.data!.todoItems

  return (
    <ul>
      {todoItems.map(item => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  )
}

Types

A key feature of GraphQL is the possibility to fetch as many or as few properties of an object as is needed for a particular view. For this reason, it is difficult to assume a specific interface for any GraphQL type.

This library generates named interfaces for every selection of fields in a query. For example, given the above mutation:

mutation createTodo($todoItem: TodoItemInput!) {
  createTodoItem(todoItem: $todoItem) {
    id
  }
}

the following types are generated:

// TodoItemInput
type TodoItemInput = {
  title: TodoItemInput_title
  description?: Nullable<TodoItemInput_description>
  dueDate?: Nullable<TodoItemInput_dueDate>
}
type TodoItemInput_title = string
type TodoItemInput_description = string
type TodoItemInput_dueDate = any

// createTodo() mutation
type createTodo_variables = {
  todoItem: createTodo_variables_todoItem
}
type createTodo_variables_todoItem = TodoItemInput
type createTodo_data = {
  createTodoItem: createTodo_data_createTodoItem
}
type createTodo_data_createTodoItem = { id: createTodo_data_createTodoItem_id }
type createTodo_data_createTodoItem_id = string

So it is easy to specify the type of the variables or result (data) of a query or mutation, or any subselection of those.

If you want to re-use a type, I suggest to use named fragments, which create types of the same name as the fragment:

fragment TodoParts on TodoItem {
  id
  title
  isDone
}

produces:

type TodoParts = {
  id: TodoParts_id
  title: TodoParts_title
  isDone: TodoParts_isDone
}
type TodoParts_id = string
type TodoParts_title = string
type TodoParts_isDone = boolean

Generator Options

You can specify some options in the codegen.yml:

schema: http://localhost:4000
documents: ./src/graphql/*.graphql
overwrite: true
generates:
  ./src/graphql/index.ts:
    - apollo-hooks-codegen
      # Options here:
      idType: any  # The Typescript type generated for GraphQL's "ID" type (defaults to string)
      scalarTypes: # The Typescript types generated for custom scalar types in the GraphQL schema (defaults to any)
        JSON: string
        UTCDate: unknown

Future Work

  • Suspense support
  • Default values