Skip to main content
Version: 5.2


npm install --save @rest-hooks/rest@5

Define a Resource

import { Resource } from '@rest-hooks/rest';

export default class ArticleResource extends Resource {
readonly id: number | undefined = undefined;
readonly title: string = '';
readonly content: string = '';
readonly author: number | null = null;
readonly tags: string[] = [];

pk() {

static urlRoot = '';

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

Default values ensure simpler types, which means less conditionals in your components.

pk() is essential to tell Rest Hooks how to normalize the data. This ensures consistency and the best performance characteristics possible.

static urlRoot is used as the basis of common url patterns

APIs quickly get much more complicated! Customizing Resources to fit your API

Use the Resource

import { useSuspense } from 'rest-hooks';
import ArticleResource from 'resources/article';

export default function ArticleDetail({ id }: { id: number }) {
const article = useSuspense(ArticleResource.detail(), { id });
return (

useSuspense() 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.)

Dispatch mutation

import { useController } from 'rest-hooks';
import ArticleResource from 'resources/article';

export default function NewArticleForm() {
const { fetch } = useController();
return (
<Form onSubmit={e => fetch(ArticleResource.create(), new FormData(}>
<FormField name="title" />
<FormField name="content" type="textarea" />
<FormField name="tags" type="tag" />

create() then takes any keyable body to send as the payload and then returns a promise that resolves to the new Resource created by the API. It will automatically be added in the cache for any consumers to display.

We use FormData in the example since it doesn't require any opinionated form state management solution. Feel free to use whichever one you prefer.

Mutations automatically update the normalized cache, resulting in consistent and fresh data.