REST Usage
- NPM
- Yarn
yarn add @rest-hooks/rest
npm install --save @rest-hooks/rest
Define the API
- TypeScript
- JavaScript
import { Entity, createResource } from '@rest-hooks/rest';
export class Article extends Entity {
id: number | undefined = undefined;
title = '';
content = '';
author: number | null = null;
tags: string[] = [];
pk() {
return this.id?.toString();
}
}
export const ArticleResource = createResource({
urlPrefix: 'http://test.com',
path: '/article/:id',
schema: Article,
});
import { Entity, createResource } from '@rest-hooks/rest';
export class Article extends Entity {
id = undefined;
title = '';
content = '';
author = null;
tags = [];
pk() {
return this.id?.toString();
}
}
export const ArticleResource = createResource({
urlPrefix: 'http://test.com',
path: '/article/:id',
schema: Article,
});
Our definitions are composed of two pieces. Our data model defined by Schema and the networking endpoints defined by RestEndpoint.
Bind the data with Suspense
- Single
- List
import { useSuspense } from 'rest-hooks';
import { ArticleResource } from 'api/article';
export default function ArticleDetail({ id }: { id: number }) {
const article = useSuspense(ArticleResource.get, { id });
return (
<article>
<h2>{article.title}</h2>
<div>{article.content}</div>
</article>
);
}
import { useSuspense } from 'rest-hooks';
import { ArticleResource } from 'api/article';
import ArticleSummary from './ArticleSummary';
export default function ArticleList() {
const articles = useSuspense(ArticleResource.getList);
return (
<section>
{articles.map(article => (
<ArticleSummary key={article.pk()} article={article} />
))}
</section>
);
}
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.)
Mutate the data
- Create
- Update
- Delete
import { useController } from 'rest-hooks';
import { ArticleResource } from 'api/article';
export default function NewArticleForm() {
const controller = useController();
return (
<Form
onSubmit={e =>
controller.fetch(ArticleResource.create, new FormData(e.target))
}
>
<FormField name="title" />
<FormField name="content" type="textarea" />
<FormField name="tags" type="tag" />
</Form>
);
}
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.
import { useController } from 'rest-hooks';
import { ArticleResource } from 'api/article';
export default function UpdateArticleForm({ id }: { id: number }) {
const article = useSuspense(ArticleResource.get, { id });
const controller = useController();
return (
<Form
onSubmit={e =>
controller.fetch(ArticleResource.update, { id }, new FormData(e.target))
}
initialValues={article}
>
<FormField name="title" />
<FormField name="content" type="textarea" />
<FormField name="tags" type="tag" />
</Form>
);
}
update then takes any keyable
body to send as the payload and then returns a promise that
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.
import { useController } from 'rest-hooks';
import { Article, ArticleResource } from 'api/article';
export default function ArticleWithDelete({ article }: { article: Article }) {
const controller = useController();
return (
<article>
<h2>{article.title}</h2>
<div>{article.content}</div>
<button
onClick={() =>
controller.fetch(ArticleResource.delete, { id: article.id })
}
>
Delete
</button>
</article>
);
}
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.