Skip to main content
Version: 5.0


npm install --save @rest-hooks/graphql

Define Endpoint and Schema

export const gql = new GQLEndpoint('');
export default gql;
import { GQLEntity } from '@rest-hooks/graphql';

export default class User extends GQLEntity {
readonly name: string | null = null;
readonly email: string = '';
readonly age: number = 0;

Entitys are immutable. Use readonly in typescript to enforce this.


Using GQLEntities is not required, but is important to achieve data consistency.

Query the Graph

import { useResource } from 'rest-hooks';
import User from 'schema/User';
import gql from 'schema/endpoint';

export const userDetail = gql.query(
(v: { name: string }) => `query UserDetail($name: String!) {
user(name: $name) {
{ user: User },

export default function UserDetail({ name }: { name: string }) {
const { user } = useResource(userDetail, { name });
return (

useResource() guarantees access to data with sufficient freshness. This means it may issue network calls, and it may suspend until the fetch completes. Param changes will result in accessing the appropriate data, which also sometimes results in new network calls and/or suspends.

  • Fetches are centrally controlled, and thus automatically deduplicated
  • Data is centralized and normalized guaranteeing consistency across uses, even with different endpoints.
    • (For example: navigating to a detail page with a single entry from a list view will instantly show the same data as the list without requiring a refetch.)

Mutate the Graph

We're using SWAPI as our example, since it offers mutations.

import { useFetcher } from 'rest-hooks';
import { GQLEndpoint, GQLEntity } from '@rest-hooks/graphql';

const gql = new GQLEndpoint('');

class Review extends GQLEntity {
readonly stars: number = 0;
readonly commentary: string = '';

const createReview = gql.mutation(
(v: {
ep: string;
review: { stars: number; commentary: string };
}) => `mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
{ createReview: Review },

export default function NewReviewForm() {
const create = useFetcher(createReview);
return (
<Form onSubmit={e => create({}, new FormData(}>
<FormField name="ep" />
<FormField name="review" type="compound" />

The first argument to GQLEndpoint.query or GQLEndpoint.mutate is either the query string or a function that returns the query string. The main value of using the latter is enforcing the function argument types.