TypeScript クライアント(@dustid/apid-client)
@dustid/apid-client は、DUST API 向けの型付き TypeScript クライアントです。DICE Web アプリケーションが本番環境で使用しているものと同じクライアントで、リクエスト型とレスポンス型は API の OpenAPI 仕様から直接生成されるため、常にサーバーと同期します。
このパッケージは、公開 npm レジストリには公開されていません。DUST が配布しており、連携をご利用のお客様はリクエストに応じて入手できます(support@dustidentity.com までお問い合わせください)。npm install @dustid/apid-client を実行しても見つかりません。
この依存関係を導入しない場合でも、OpenAPI 仕様から型を生成することで同等の型安全性を確保し、通常の fetch で API を呼び出せます。このクライアント自体の型も、まさにこの方法で生成されています。クイックスタートでは、何もインストールせずに実行できるよう、この方法を採用しています。
導入する場合の前提条件
Section titled “導入する場合の前提条件”クライアントの利用を前提に計画する前に、以下を確認してください。
| 要件 | 詳細 |
|---|---|
| ランタイム | グローバルな fetch:Node.js 18 以降、Bun、または Deno。fetcher オプションを使用して、独自の実装(プロキシ、再試行、テストダブル)を注入できます。 |
| TypeScript ツールチェーン | このパッケージのエントリーポイントは、コンパイル済み JavaScript ではなく TypeScript ソースに解決されます。バンドラーまたはランタイムでトランスパイルする必要があります。トランスパイルされていないソースに対して通常の node dist/app.js を実行しても動作しません。 |
| ランタイム依存関係 | このクライアントは依存関係がないわけではありません。エラーペイロードの検証に使用する arktype と、配布物に含まれる DUST 内部のヘルパーパッケージが依存関係として宣言されています。ベンダリング、ライセンスレビュー、またはエアギャップ環境へのインストールを行う場合は、これらも考慮してください。 |
| 実行場所 | サーバー側のみ — このページの末尾にある注意事項を参照してください。 |
クライアントを構築する
Section titled “クライアントを構築する”import { ApidClient } from "@dustid/apid-client";
const client = new ApidClient({ baseUrl: "https://apid.dustid.io", bearerToken: token, // Authorization: Bearer <token> organizationId: orgId, // sent as Dust-Ctx-Org-Id teamId: teamId, // sent as Dust-Ctx-Team-Id});完全なオプション型は次のとおりです。
type ApidClientOptions = { baseUrl: string; bearerToken?: string; organizationId?: string; // Dust-Ctx-Org-Id header teamId?: string; // Dust-Ctx-Team-Id header fetcher?: typeof globalThis.fetch; // custom fetch (proxies, testing) defaultHeaders?: HeadersInit | (() => HeadersInit); // e.g. Dust-Ctx-Locale logger?: Logger; // debug/error request logging};organizationId と teamId はコンテキストヘッダーに対応します。teamId を省略すると、サーバーはデフォルトで組織のルートチームを使用します。すべてのリクエストに追加したいものがある場合は、defaultHeaders を使用してください。たとえば、エラーメッセージをローカライズできます。
const client = new ApidClient({ baseUrl, bearerToken, organizationId, defaultHeaders: { "Dust-Ctx-Locale": "zh-CN" },});コンテキストまたはトークンの切り替え
Section titled “コンテキストまたはトークンの切り替え”クライアントはイミュータブルです。2 つのヘルパーは再設定されたコピーを返すため、リクエスト単位またはユーザー単位の範囲指定を低コストで行えます。
const asOtherTeam = client.withContext({ teamId: otherTeamId });const asFreshToken = client.withToken(newBearerToken);リソースと呼び出し
Section titled “リソースと呼び出し”クライアントはエンドポイントを、client.me、client.threads、client.bundles、client.files、client.tags(識別子の操作 — /api/v1/tags/* エンドポイント)、client.teams、client.sharing、client.templates、client.events、client.relations、client.threadLinks、client.assemblies、client.transfers、client.slices、client.imports、client.fabric、client.users、client.certificates、および client.certificateForms というリソースに分類しています。
メソッド名はリファレンスに対応しています。スレッドを使用した実際の例を 2 つ示します。
// GET /api/v1/threads — cursor-paginated listconst page = await client.threads.list({ pageSize: 50, q: "tire" });for (const thread of page.threads) { console.log(thread.threadId, thread.name);}if (page.next) { const nextPage = await client.threads.list({ pageSize: 50, cursor: page.next });}// POST /api/v1/threads — create, unwrapped to the single created recordconst created = await client.threads.createOne({ type: "single", thread: { name: "Tire SZ3J-11-ZJ17" }, data: [{ name: "Serial Number", type: "text", value: { text: "SZ3J-11-ZJ17" } }],});
// GET /api/v1/threads/{thread_id}const record = await client.threads.get(created.threadId);console.log(record.thread.name, record.events.length);threads.create は未加工のバッチレスポンス({ created, uploadResponses })を返します。threads.createOne は created[0] を返す便利なメソッドで、サーバーが何も作成しなかった場合は例外をスローします。
すべてのリクエスト型とレスポンス型(ThreadCreateRequest、ThreadQueryResponse、ThreadGetResponse、…)は、仕様から生成された未加工の paths / components / operations 型とともに、パッケージルートからエクスポートされます。
メソッドは成功時に解析済みの JSON レスポンスを返し、2xx 以外のステータスでは必ず ApiError をスローします。ApiError には、API の標準エラー本文が含まれます。
import { ApiError } from "@dustid/apid-client";
try { await client.threads.get(threadId);} catch (error) { if (error instanceof ApiError) { // error.code stable error code, e.g. "NOT_FOUND", "UNAUTHORIZED" // error.status HTTP status number // error.message localized human-readable message // error.detail optional extra context (validation issues, etc.) // error.body the full { code, message, status, detail } payload if (error.code === "UNAUTHORIZED") { // token expired — re-exchange the API key and retry } } else { throw error; // network failure or non-JSON response }}把握しておくべき境界的な挙動が 2 つあります。204/205 レスポンスは undefined に解決され、有効な JSON ではないレスポンスでは通常の Error(ApiError ではありません)がスローされます。logger を渡すと、サポートでの照合に使用できる x-request-id とともに、失敗したすべてのリクエストがログに記録されます。
代替手段:独自に型を生成する
Section titled “代替手段:独自に型を生成する”API は、OpenAPI 3 仕様を https://apid.dustid.io/api/openapi.json で提供しています。openapi-typescript を使用すると、この仕様を完全に型付けされた paths/components 定義に変換でき、通常の fetch または仕様駆動の任意の fetch ラッパーで利用できます。
npx openapi-typescript@7 https://apid.dustid.io/api/openapi.json -o <generated-types-file>import type { paths } from "./dust-api";
type ThreadList = paths["/api/v1/threads"]["get"]["responses"]["200"]["content"]["application/json"];Authorization、Dust-Ctx-Org-Id、および Dust-Ctx-Team-Id ヘッダーは、ご自身で設定してください。リクエスト規約を参照してください。新しい API 機能を取り込むたびに型を再生成してください。/api/openapi.json の仕様は、取得元のサーバーに対して常に最新です。
- API クイックスタート — 通常の
fetchを使用した同じエンドツーエンドのフローです。依存関係を導入するか決める前に実行できます。 - リクエスト規約 — クライアントが実装するヘッダーとエラー契約です。
- エラーとスキャン結果 —
ApiErrorの背後にあるコードと、スキャンの結果表です。 - 完全な API リファレンス — すべてのエンドポイントとスキーマです。