关于 data-client-rest
data-client-rest 是面向 React/TypeScript 应用的编码技能,指导如何用 @data-client/rest 建模并访问 REST API。内容涵盖资源、端点、类型安全、数据规范化与缓存管理。
主要功能
- 01定义 CRUD 资源与端点
- 02声明式数据模式
- 03REST 请求与变更操作
- 04乐观更新配置
- 05扩展资源端点
适用场景
- 01为 API 数据定义类型安全模型
- 02实现列表查询和分页
- 03编写 REST 数据更新逻辑
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ reactive/ data-client --skill data-client-rest安装后在 Claude Code 中输入/data-client-rest确认已加载。
详细介绍
指南:使用 @data-client/rest 进行资源建模
本项目使用 @data-client/rest,在 React/TypeScript 应用中以类型安全的方式定义、获取、规范化和更新 RESTful 资源及实体,并自动管理缓存。
生成与远程 API 交互的代码时,务必遵循这些模式。
1. 定义架构
本项目使用架构以类型安全的方式定义和规范化数据模型,并自动管理缓存。有关架构模式,请使用技能“data-client-schema”。 生成可变数据定义时,务必遵循这些模式(使用技能“data-client-schema”)。
2. 资源(resource())
- resource() 会为常见对象的 CRUD 操作创建一组 RestEndpoints
- 必填字段:
path:path‑to‑regexp 模板(带类型!)schema:单个项目的声明式数据结构(通常为 Entity 或 Union)
- 可选字段:
urlPrefix:主机根路径,如果不是/searchParams:MyResource.getList 中查询参数的类型(TS 泛型)paginationField:添加 MyResource.getList.getPage 用于分页optimistic:布尔值;为 true 时,所有变更都会乐观更新,从而提升性能body:MyResource.getList.push、MyResource.getList.unshift、MyResource.update、MyResource.partialUpdate 的 body 参数类型
import { Entity, resource } from '@data-client/rest';
import { User } from './User';
export class Todo extends Entity {
id = 0;
user = User.fromJS();
title = '';
completed = false;
createdAt = new Date();
static key = 'Todo';
static schema = {
user: User,
createdAt: (iso: string) => new Date(iso),
}
}
export const TodoResource = resource({
urlPrefix: 'https://jsonplaceholder.typicode.com',
path: '/todos/:id',
schema: Todo,
searchParams: {} as { userId?: string | number } | undefined,
paginationField: 'page',
nonFilterArgumentKeys: ['orderBy'],
optimistic: true,
});
用法
渲染
// GET https://jsonplaceholder.typicode.com/todos/5
const todo = useSuspense(TodoResource.get, { id: 5 });
// GET https://jsonplaceholder.typicode.com/todos
const todoList = useSuspense(TodoResource.getList);
// GET https://jsonplaceholder.typicode.com/todos?userId=1
const todoListByUser = useSuspense(TodoResource.getList, { userId: 1 });
变更
const ctrl = useController();
// PUT https://jsonplaceholder.typicode.com/todos/5
const updateTodo = todo => ctrl.fetch(TodoResource.update, { id }, todo);
// PATCH https://jsonplaceholder.typicode.com/todos/5
const partialUpdateTodo = todo =>
ctrl.fetch(TodoResource.partialUpdate, { id }, todo);
// POST https://jsonplaceholder.typicode.com/todos
const addTodoToStart = todo =>
ctrl.fetch(TodoResource.getList.unshift, todo);
// POST https://jsonplaceholder.typicode.com/todos?userId=1
const addTodoToEnd = todo => ctrl.fetch(TodoResource.getList.push, { userId: 1 }, todo);
// PATCH https://jsonplaceholder.typicode.com/todos/5
const toggleStatus = (completed: boolean) => ctrl.fetch(TodoResource.getList.move, { id }, { completed });
// DELETE https://jsonplaceholder.typicode.com/todos/5
const deleteTodo = id => ctrl.fetch(TodoResource.delete, { id });
// GET https://jsonplaceholder.typicode.com/todos?userId=1&page=2
const getNextPage = (page) => ctrl.fetch(TodoResource.getList.getPage, { userId: 1, page })
如需了解更详细的用法,请使用技能“data-client-react”或“data-client-vue”。
3. 自定义 RestEndpoint 模式
/** Stand‑alone endpoint with custom typing */
export const getTicker = new RestEndpoint({
urlPrefix: 'https://api.exchange.coinbase.com',
path: '/products/:product_id/ticker',
schema: Ticker,
pollFrequency: 2000,
});
类型提示
path是第一个参数的 path‑to‑regexp 模板method≠GET⇒ 第二个参数为 body(除非body: undefined)- 提供
searchParams/body值 仅用于类型推断 - 从
RestEndpoint继承时使用RestGenerics
getOptimisticResponse()
getOptimisticResponse(snap, { id }) {
const article = snap.get(Article, { id });
if (!article) throw snap.abort;
return {
id,
votes: article.votes + 1,
};
}
RestEndpoint 生命周期方法
- 执行获取:
fetchResponse()→parseResponse()→process()- url(urlParams):
urlPrefix+path+(searchParams→searchToString()) - getRequestInit(body):
getHeaders()+method+signal
- url(urlParams):
4. 扩展资源
使用 .extend() 添加或覆盖端点。
export const IssueResource = resource({
// ...base config...
}).extend((Base) => ({
search: Base.getList.extend({
path: '/search/issues',
// ...custom schema or params...
}),
}));
5. 最佳实践与说明
- 当要求浏览或导航到某个网址时,实际访问该网址
- 始终为每个 resource/entity/collection 设置
schema,以便进行规范化 - 定义单个端点或不存在变更端点时,优先使用
RestEndpoint而不是resource() - 对于 blob/文件下载及其他非 JSON 响应,请参阅 network-transform: 文件下载。
6. 应避免的常见错误
- 不要在不使用或不需要变更端点时使用
resource()
参考资料
如需详细的 API 文档,请参阅 references 目录:
- resource - 创建 CRUD 端点
- RestEndpoint;_EndpointLifecycle.md;RestEndpoint.js - 单个 REST 端点
- Entity;_entity_lifecycle_methods.md - 规范化数据类
- Collection - 可变列表
- schema - Schema 概览
- Fixtures - 用于测试的模拟数据
- data-dependency;_useLive.md;_AsyncBoundary.md - 渲染指南
- mutations;_useLoading.md;_VoteDemo.md - 变更指南
指南(用户询问这些主题时请参考):
- auth - 身份验证标头、令牌、登录/登出流程
- pagination;_pagination.md - 游标/偏移分页、无限滚动
- optimistic-updates;_optimisticTransform.md - 在服务器响应前提供即时 UI 反馈
- network-transform - 转换响应、处理非标准 API
概念(用户询问这些主题时请参考):
- expiry-policy - 缓存失效、陈旧数据、dataExpiryLength、errorExpiryLength
- error-policy - 错误处理、重试行为、软错误与硬错误
务必遵循这些模式,并参考官方文档了解边缘情况。优先生成符合惯例、类型安全的代码,并通过 schema 定义利用自动规范化/缓存。
评论
支持 Markdown