- NPM
- Yarn
- pnpm
- esm.sh
yarn add @data-client/rest
npm install --save @data-client/rest
pnpm add @data-client/rest
<script type="module">
import * from 'https://esm.sh/@data-client/rest';
</script>
Defina os Resources
Resources são uma coleção de métodos (methods) para um determinado modelo de dados (data model). Entities e Schemas são o modelo de dados declarativo.
RestEndpoint são os métodos sobre
esses dados.
- Class
- Mixin
import { Entity, resource } from '@data-client/rest'; import { User } from './User'; export class Article extends Entity { slug = ''; title = ''; content = ''; author = User.fromJS(); tags: string[] = []; createdAt = Temporal.Instant.fromEpochMilliseconds(0); pk() { return this.slug; } static key = 'Article'; static schema = { author: User, createdAt: Temporal.Instant.from, }; } export const ArticleResource = resource({ urlPrefix: 'http://test.com', path: '/article/:slug', searchParams: {} as { userId?: string } | undefined, schema: Article, paginationField: 'page', });
import { EntityMixin, resource } from '@data-client/rest'; import { UserEntity } from './User'; export class Article { slug = ''; title = ''; content = ''; author = UserEntity.fromJS(); tags: string[] = []; createdAt = Temporal.Instant.fromEpochMilliseconds(0); } export class ArticleEntity extends EntityMixin(Article, { schema: { author: UserEntity, createdAt: Temporal.Instant.from, }, key: 'Article', pk: 'slug', }) {} export const ArticleResource = resource({ urlPrefix: 'http://test.com', path: '/article/:slug', searchParams: {} as { userId?: string } | undefined, schema: ArticleEntity, paginationField: 'page', });
Entity é um tipo de schema que tem uma chave primária (pk). É isso que nos permite evitar a duplicação de estado, uma das principais escolhas de design que possibilitam características tão elevadas de segurança e desempenho.
O static schema nos permite especificar transformações declarativas, como a desserialização automática de campos com createdAt e o aninhamento do campo author.
As urls são construídas combinando o urlPrefix com path templating.
O TypeScript exige os argumentos especificados com dois-pontos como prefixo, como :slug neste exemplo.
// GET http://test.com/article/use-reactive-data-client
ArticleResource.get({ slug: 'use-reactive-data-client' });
Renderize os dados
- Single
- List
- Server Component
import { useSuspense } from '@data-client/react';
import { ArticleResource } from '@/resources/Article';
export default function ArticleDetail({ slug }: { slug: string }) {
const article = useSuspense(ArticleResource.get, { slug });
return (
<article>
<h2>{article.title}</h2>
<div>{article.content}</div>
</article>
);
}
useSuspense() age como await, garantindo que os dados estejam disponíveis antes de retornar. Saiba como declarar suas dependências de dados
import { useSuspense } from '@data-client/react';
import { ArticleResource } from '@/resources/Article';
import ArticleSummary from './ArticleSummary';
export default function ArticleList({ userId }: { userId?: number }) {
const articles = useSuspense(ArticleResource.getList, { userId });
return (
<section>
{articles.map(article => (
<ArticleSummary key={article.pk()} article={article} />
))}
</section>
);
}
useSuspense() age como await, garantindo que os dados estejam disponíveis antes de retornar. Saiba como declarar suas dependências de dados
import { useSuspense } from '@data-client/react';
import { ArticleResource } from '@/resources/Article';
import ArticleSummary from './ArticleSummary';
export default async function ArticleList({ params }: { params: { userId: number } }) {
const articles = await ArticleResource.getList(params);
return (
<section>
{articles.map(article => (
<ArticleSummary key={article.pk()} article={article} />
))}
</section>
);
}
Server Components tornam os dados estáticos e imutáveis.
Altere os dados
- Create
- Update
- Delete
import { useController } from '@data-client/react';
import { ArticleResource } from '@/resources/Article';
export default function NewArticleForm() {
const ctrl = useController();
return (
<Form
onSubmit={e =>
ctrl.fetch(ArticleResource.getList.push, new FormData(e.target))
}
>
<FormField name="title" />
<FormField name="content" type="textarea" />
<FormField name="tags" type="tag" />
</Form>
);
}
getList.push recebe então qualquer body keyable para enviar como payload e retorna uma promise que
resolve para o novo Resource criado pela API. Ele será adicionado automaticamente ao cache para que qualquer consumidor o exiba.
import { useController, useSuspense } from '@data-client/react';
import { ArticleResource } from '@/resources/Article';
export default function UpdateArticleForm({ slug }: { slug: string }) {
const article = useSuspense(ArticleResource.get, { slug });
const ctrl = useController();
return (
<Form
onSubmit={e =>
ctrl.fetch(ArticleResource.update, { slug }, new FormData(e.target))
}
initialValues={article}
>
<FormField name="title" />
<FormField name="content" type="textarea" />
<FormField name="tags" type="tag" />
</Form>
);
}
update recebe então qualquer body keyable para enviar como payload e retorna uma promise que
recebe então qualquer body keyable para enviar como payload e retorna uma promise que
resolve para o novo Resource criado pela API. Ele será adicionado automaticamente ao cache para que qualquer consumidor o exiba.
import { useController } from '@data-client/react';
import { Article, ArticleResource } from '@/resources/Article';
export default function ArticleWithDelete({
article,
}: {
article: Article;
}) {
const ctrl = useController();
return (
<article>
<h2>{article.title}</h2>
<div>{article.content}</div>
<button
onClick={() =>
ctrl.fetch(ArticleResource.delete, { slug: article.slug })
}
>
Delete
</button>
</article>
);
}
Usamos FormData no exemplo porque ele não exige nenhuma solução opinativa de gerenciamento de estado de formulários. Sinta-se à vontade para usar a que preferir.
Mutações atualizam automaticamente todos os usos, sem necessidade de requisições adicionais.
Ao usar TypeScript (opcional), é necessária a versão 4.0 ou superior.
Agent Skills para REST
- Skills
- OpenSkills
- Claude Code
npx skills add reactive/data-client \
--skill data-client-schema \
--skill data-client-rest-setup \
--skill data-client-rest
npx openskills install reactive/data-client/.agents/skills/data-client-schema
npx openskills install reactive/data-client/.agents/skills/data-client-rest-setup
npx openskills install reactive/data-client/.agents/skills/data-client-rest
claude plugin marketplace add reactive/data-client
claude plugin install core@data-client
Em seguida, chame /data-client-rest-setup para migrar
Migrando do Axios
A skill data-client-rest-setup detecta automaticamente o uso do axios e aplica a migração do axios — incluindo o codemod, a conversão de interceptors e a migração do tratamento de erros.
Veja o Guia de migração do Axios completo para exemplos passo a passo, uma tabela de referência rápida e um codemod independente.