mcpField
D
data-client-rest

data-client-rest

github.com/reactive開発2.0k38 回インストール今日更新
リポジトリ

data-client-rest について

data-client-restは、React/TypeScriptアプリで@data-client/restを使い、REST APIをモデル化して利用するためのコーディングスキルです。型付きスキーマ、正規化、キャッシュ管理に加え、リソースやエンドポイントの設計を扱います。

主な機能

  1. 01CRUDリソースとエンドポイントの定義
  2. 02データスキーマの宣言
  3. 03RESTデータの取得と更新
  4. 04楽観的更新の設定
  5. 05リソースエンドポイントの拡張

活用シーン

  1. 01型付きAPIデータモデルの作成
  2. 02リスト取得とページネーションの実装
  3. 03RESTデータ更新処理の作成

インストール

コマンドをコピーしてターミナルで実行します。

$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 は第 1 引数用の path-to-regexp テンプレートです
  • method ≠ GET ⇒ 第 2 引数は 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

4. リソースの拡張

.extend() を使用して、エンドポイントを追加またはオーバーライドします。

export const IssueResource = resource({
  // ...base config...
}).extend((Base) => ({
  search: Base.getList.extend({
    path: '/search/issues',
    // ...custom schema or params...
  }),
}));

5. ベストプラクティスと注意事項

  • ウェブアドレスを閲覧または移動するよう求められた場合は、実際にそのアドレスにアクセスしてください
  • 正規化のため、すべてのリソース/エンティティ/コレクションに必ず schema を設定してください
  • 単一のエンドポイントを定義する場合や、ミューテーションエンドポイントが存在しない場合は、resource() より RestEndpoint を優先してください
  • blob/ファイルのダウンロードや、その他の非 JSON レスポンスについては、network-transform: ファイルのダウンロードを参照してください。

6. 避けるべきよくある間違い

  • ミューテーションエンドポイントを使用しない、または必要としない場合は、resource() を使用しないでください

リファレンス

API の詳細なドキュメントについては、references ディレクトリを参照してください。

ガイド(ユーザーがこれらのトピックについて尋ねた場合に参照してください):

概念(ユーザーがこれらのトピックについて尋ねた場合に参照してください):

  • expiry-policy - キャッシュの無効化、古いデータ、dataExpiryLength、errorExpiryLength
  • error-policy - エラー処理、再試行の動作、ソフトエラーとハードエラー

必ずこれらのパターンに従い、エッジケースについては公式ドキュメントを参照してください。スキーマ定義による自動正規化/キャッシュを活用した、慣用的で型安全なコードの生成を優先してください。

コメント