objectstack-api について
objectstack-api は、ObjectStack の HTTP API 設計・記述を支援するスキルです。自動生成されるデータルート、宣言的エンドポイント、アクセス方針、エンドポイントの制約を扱います。
主な機能
- 01オブジェクト向け REST ルートの自動生成
- 02apis によるエンドポイント宣言
- 03API メソッドとアクセス方針の指針
- 04エンドポイントのマッピングと命名規則
- 05公開フォームエンドポイントの仕様
活用シーン
- 01ObjectStack オブジェクトの CRUD・クエリルート設計
- 02データまたはフローパイプラインに委譲するエンドポイントの宣言
- 03匿名フォーム送信とエンドポイントアクセスの確認
- 04宣言的 API 定義を含むスタックのアップグレード
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ objectstack-ai/ objectstack --skill objectstack-apiインストール後、Claude Code で/objectstack-apiを入力して読み込まれたか確認します。
同梱ファイルreferences/_index.mdevals/endpoints-auth-routes.json
詳細
API 設計 — ObjectStack API プロトコル
スキルの範囲
| 必要なこと | 代わりに使用 |
|---|---|
| オブジェクト、フィールド、権限、またはデータソースをモデル化する | objectstack-data |
| リクエストをフィルター、ソート、ページネーション、または集計する | objectstack-query |
| カーネルサービスを登録する、またはプラグインから読み取る | objectstack-platform |
| ルートガードまたは認証述語で CEL を使用する | objectstack-formula |
自動生成 API とカスタム API
自動生成 API
apiEnabled: true(デフォルト)を持つすべての ObjectStack オブジェクトには、
完全な REST API が自動的に生成されます。
GET /api/v1/data/{object} # List records (with filter, sort, pagination)
GET /api/v1/data/{object}/:id # Get single record
POST /api/v1/data/{object} # Create record
PATCH /api/v1/data/{object}/:id # Update record
DELETE /api/v1/data/{object}/:id # Delete record (hard delete)
POST /api/v1/data/{object}/query # Complex queries + aggregation (QueryAST in body)
POST /api/v1/data/{object}/batch # Per-object batch operations
POST /api/v1/batch # Cross-object atomic batch
データの CRUD は /data プレフィックスの下にあります。/bulk ルートも
GET .../aggregate ルートもありません。バッチ書き込みは batch エンドポイント経由で行い、
集計はリクエスト本文の groupBy/aggregations を指定して
POST /api/v1/data/{object}/query 経由で行います。
重要なルール: オブジェクトで
apiMethodsを定義すると、その操作(および そこから派生する操作)のみが公開されます。[]はすべて拒否することを意味します。定義可能な 値は6つのプリミティブです。**API メソッド(操作)**を参照してください。
メタデータ API(/meta)
メタデータの読み取り用エンドポイントは、上記のデータ CRUD ルートとは別に、
/api/v1/meta の下にあります。
GET /api/v1/meta/:type # List metadata items of a type (object, view, flow, doc, …)
GET /api/v1/meta/:type/:name # Read a single metadata item
読み取り側のクエリパラメーター(?preview=draft、?package=、?include=content)は
クライアントの契約であり、これらを宣言するスタックはありません。
公開(匿名)フォームエンドポイント
FormView は、sharing に次の3つすべてが宣言されている場合に限り、匿名フォームエンドポイントで
提供されます。enabled: true(スキーマのデフォルトは
false)、allowAnonymous: true、および publicLink スラッグです。いずれか1つでも
欠けていると、両方のエンドポイントは 404 FORM_NOT_FOUND を返します。その後、フォームは次の場所に
マウントされます。
GET /api/v1/forms/:slug # returns form spec + restricted objectSchema
POST /api/v1/forms/:slug/submit # whitelist-filtered INSERT, no auth header
これらのエンドポイントは enforceAuth を迂回します(Web-to-Lead/Web-to-Case フロー)。送信はフォーム独自の
宣言によって許可されます。送信先オブジェクトに対する publicFormGrant(新しい行の作成と読み戻しのみで、
それ以外は許可されません)は、権限セットが解決される前に判定されます。送信コンテキストの
guest_portal という名前には何の権限もなく、セットも不要です。この名前のセットがある場合も、
その結果マスカーにのみ適用されます。フレームワークはフォームの sections[].fields[] リストにない
フィールドを除去します。送信先オブジェクトの beforeInsert フックでは、安全なデフォルト値
(status='new'、lead_source='web' など)を設定し、権限の強いキー
(owner、internal_notes など)を delete してください。組織列によってオブジェクトが壁で隔てられている
制限付きの構成(group/isolated)では、そのオブジェクト上のフォームも提供されません。両方のエンドポイントが
404 を返し、保存/公開時には public-form-intake-unavailable の警告が表示されます。組織に
属さない行を扱うオブジェクトで再び利用できるようにするには、そのオブジェクトで
tenancy: { enabled: false } を宣言してください。完全な仕様については、
node_modules/@objectstack/spec/src/ui/view.zod.ts(FormViewSchema)および
node_modules/@objectstack/spec/src/ui/sharing.zod.ts(enabled/allowAnonymous/publicLink
を含む SharingConfigSchema)を参照してください。
宣言型エンドポイント(apis:)— ハンドラーコード不要
defineStack({ apis }) は HTTP エンドポイントをメタデータとして宣言します。宣言された
エンドポイントはプロトコル17から利用可能です。ランタイムは
METHOD + path を照合し、エンドポイントのポリシーキーを実行してから、組み込みルートと
同じパイプラインに処理を委譲します。object_operation は /api/v1/data/{object} の背後にある
データパイプラインへ、flow は POST /api/v1/automation/{name}/trigger の背後にある自動化パイプラインへ
委譲されます。エンドポイントとは、既存のパイプラインに対する安定した URL とポリシーレイヤーであり、
別の実行方式ではありません。
apis: とコードハンドラーの選択
| 用途 | 場合 |
|---|---|
defineStack({ apis }) | エンドポイントが、プラットフォームがすでに実行するものの投影である場合:レコードをクエリして返す、またはフローをトリガーする場合です。コードもデプロイアーティファクトも不要で、公開時のゲートで検証されます。こちらを優先してください。 |
| コードを実行するフロー | エンドポイントで実際のハンドラー CODE が必要な場合:type: 'flow' エンドポイントを、スタック関数を指定する script ノード(defineStack({ functions }))を持つフロー、または宣言済みコネクターを呼び出す connector_action ノードを持つフロー(アウトバウンド)に向けます。URL は宣言的なままで、コードはオートメーション機能がすでに実行されている場所で実行されます。 |
制御下にある送信元からの受信 Webhook は、type: 'api' フローです
(objectstack-automation → 受信 Webhook(api)トリガー)。ObjectStack 独自の x-objectstack-signature を検証し、キューに登録して、202 を返します。
アプリが http.server にマウントされることはありません。このサービスはプラットフォームプラグイン独自のドア構築プリミティブであり、コードでマウントしたルートには、呼び出し元の ID、認証ゲート、レート制限、名前空間の割り当て、OpenAPI エントリーが付与されません。現在、アプリの機能として提供されていないケースが3つあります。存在しない機能を作り上げず、その旨を伝えてください。生のボディに対する独自の署名で検証されるサードパーティーのコールバック(フックが確認するのは x-objectstack-signature のみ)、ストリーミングレスポンス(宣言されたエンドポイントは1つの JSON エンベロープを返します)、そしてプラットフォームが対応していないプロトコルです。
import type { ApiEndpoint } from '@objectstack/spec/api';
// The stack declares `manifest: { namespace: 'acme', … }` — required, see below.
export const leadFeed: ApiEndpoint = {
name: 'acme_lead_feed',
path: '/api/v1/apps/acme/leads', // /api/v1/apps/<namespace>/<subpath>
method: 'GET',
summary: 'Lead feed',
type: 'object_operation',
objectParams: { object: 'acme_lead', operation: 'find' },
// `authRequired` omitted → defaults to `true`. Omission is SAFE.
cacheTtlSeconds: 30, // GET-only; rides success answers only
};
パスの例外(ADR-0121 D1/D2)
宣言するパスは /api/v1/apps/<manifest.namespace>/<subpath> でなければなりません。名前を指定できるのはサブパスのみで、その内部には以下の通常の命名規則が適用されます。manifest.namespace は明示的に宣言する必要があり、manifest.id から導出されることはありません。この範囲外のパスは公開時に拒否されます。
5つの公開ゲートと、それぞれの対処方法
このランタイムが処理できない宣言は、ゲートごとに公開時に拒否されます。ゲートの文言を暗記する必要はありません。拒否メッセージを読んでください。そこに修正方法が記載されています。5つのゲートは、名前空間(上記の例外)、サポート対象のターゲット(script / proxy は 17.x では実行されません。object_operation には objectParams.object と .operation の両方が必要です。flow には target が必要です)、マッピング(以下)、ポリシー(以下)、一意性(スタックごとに METHOD + パスの組み合わせは1つのみ)です。
authRequired と D6 の組み合わせ
authRequired のデフォルトは true なので、省略しても安全です。明示的に false に設定すると、認証なしで実行できるエントリーポイントが開きます。その場合は ADR-0121 D6 により、有効化された予算を組み合わせる必要があります。
authRequired: false,
rateLimit: { enabled: true, windowMs: 60_000, maxRequests: 100 },
ゲートの判定条件は rateLimit.enabled === true であり、キーの存在ではありません。RateLimitConfigSchema.enabled 自体のデフォルトは false なので、windowMs / maxRequests のみを記述しても、何も計測されない予算を宣言することになります。エンドポイントの予算は、サーバーレベルの server.security.rateLimit とは独立して計測されます。
マッピングキー:投影のみ
inputMapping / outputMapping は、ドットパスでフィールドを移動および名前変更するだけで、それ以上のことはできません。inputMapping はリクエストボディをマッピングし、ポリシーチェーンの適用後、委譲の前に実行されます(したがって、マッピングによって呼び出し元が authRequired やレート制限を回避することはできません)。outputMapping は、成功したレスポンスボディにのみ適用されます。作成する前に知っておくべき重要な点は3つあります。
transformは拒否されます。変換関数レジストリーはありません。 値は生成される場所(フローまたは数式フィールド)で計算してください。- リクエストボディを読み取らない
find/get/deleteのobject_operationでは、inputMappingは拒否されます。 - 複数のエントリーで同じターゲットパスに書き込むことはできません。また、一方が他方の配下にあるパス(
xとx.y)も指定できません。
バージョン 17 未満のスタックからのアップグレード
古いメジャーバージョン向けに記述された apis: ブロックは、1 バイトも変更されずに意味が変わります。実行されないドキュメントが、実行エントリーポイントになります。アップグレード前に、プロトコルアップグレードガイドの declarative-apis-endpoints-live の項目を確認してください。これは名前の変更ではなく、セキュリティレビューです。重要な手順は 2 つです。すべての path を例外枠に移すことと、各エントリーを検索して authRequired: false がないか確認することです。
エンドポイントの命名規則
| パターン | 用途 | 例 |
|---|---|---|
/api/v1/data/{object} | 自動生成されるコレクション | /api/v1/data/accounts |
/api/v1/data/{object}/:id | 自動生成されるレコード | /api/v1/data/accounts/abc123 |
/api/v1/{object}/:id/{action} | レコードに対するカスタムアクション | /api/v1/cases/:id/close |
/api/v1/{domain}/{action} | ドメインレベルのアクション | /api/v1/ai/chat |
/api/v1/apps/{namespace}/{subpath} | 宣言型 apis: エンドポイント — 例外枠であり、自由に選べるものではありません | /api/v1/apps/acme/leads |
ルール:
- コレクションのパスには、必ず複数形の名詞を使ってください(
accountではなくaccounts)。 - 複数語のパスには snake_case を使ってください(
projectTasksではなくproject_tasks)。 - 動詞は CRUD ではなく、アクションにのみ使ってください(
/close、/approve)。 - バージョン管理のため、必ず
/api/v1/をプレフィックスとして付けてください。
API メソッド(オペレーション)
作成者が指定できる ApiMethod 列挙型は、6 つの基本操作です。より広い実効語彙(14 個の値)は、ゲートとレスポンスが使用するもので、追加の 8 つの動詞が apiMethods で宣言されることはありません。
作成者が指定できる基本操作:
| メソッド | 現在の HTTP インターフェイス | 目的 |
|---|---|---|
get | GET /data/{object}/:id | 単一のレコードを取得する |
list | GET /data/{object} | フィルター、並べ替え、ページネーションを指定してレコードを一覧表示する |
create | POST /data/{object} | 新しいレコードを作成する |
update | PATCH /data/{object}/:id | 既存のレコードを更新する |
delete | DELETE /data/{object}/:id | レコードを削除する |
bulk | POST /data/{object}/batch | 作成、更新、削除を一括処理する(bulk ∧ 子オペレーション) |
派生オペレーション(自動的に許可され、作成者が指定することはありません):
| オペレーション | 派生元 | 現在の HTTP インターフェイス |
|---|---|---|
upsert | create ∧ update | 生成されません |
aggregate | list | groupBy/aggregations を指定した POST /data/{object}/query |
search | list ∧ searchable | グローバルな GET /api/v1/search。オブジェクト単位ではありません |
import | create ∨ update(writeMode による厳密な判定) | POST /data/{object}/import |
export | list | GET /data/{object}/export |
history(get ∧ trackHistory から派生)はゲートのみを制御します。restore/purge は派生されません。ごみ箱のインターフェイスは廃止されています。派生動詞を apiMethods で宣言すると、解析時に削除され、FROM → TO の警告が表示されます。
ディスカバリーとヘルスチェック
GET /api/v1/health、GET /ready(実行中は 200/起動中は 503)、GET /api/v1/discovery(サービスごとのステータス)は、すべてのデプロイ環境に存在します。3 つともレスポンス用のインターフェイスであり、定義する必要はありません。
ディスパッチャーのエラーコード
HttpDispatcher は中央のリクエストルーターで、次のように応答します。
| HTTP ステータス | エラーコード | 発生条件 |
|---|---|---|
| 404 | ROUTE_NOT_FOUND | パスに一致するルートがありません |
| 405 | METHOD_NOT_ALLOWED | ルートは存在しますが、メソッドがサポートされていません |
| 501 | NOT_IMPLEMENTED | ルートは宣言されていますが、ハンドラーはスタブです |
| 503 | SERVICE_UNAVAILABLE | サービスは登録されていますが、準備ができていません |
リアルタイムサブスクリプション
リアルタイムの契約はポインタースタイルです。正確な形状は仕様ソースを参照してください。
node_modules/@objectstack/spec/src/api/realtime.zod.ts—TransportProtocol(websocket|sse|polling)、SubscriptionSchema(id、events[]、transport、任意のchannel)、RealtimeEventSchema、およびRealtimeConfigSchema。node_modules/@objectstack/spec/src/api/websocket.zod.ts— WebSocket メッセージプロトコル:subscribe/unsubscribe メッセージ、イベント配信、プレゼンス、 カーソルおよび共同編集メッセージ、ack/error/ping/pong フレーム。
認証と認可
RBAC(definePermissionSet)とRLSはobjectstack-data側の機能であり、このセクションでは
エンドポイント独自の認証キーを扱います。
認証設定
エンドポイントにネストされた auth ブロックや、name/request/
response フィールドはありません。認証は RestApiEndpointSchema 上の
フラットな public + permissions のペアであり、宣言型の
ApiEndpointSchema エンドポイント(およびディスパッチャー)では
authRequired: boolean(デフォルトは true)を使用します。これを false に
設定する場合は、rateLimit を必ず設定してください(ADR-0121 D6 — 上記の
宣言型エンドポイント →
authRequired とD6の組み合わせを参照)。レート制限ポリシー自体は
RateLimitConfigSchema によって定義されます。
import { RateLimitConfigSchema, type RateLimitConfig } from '@objectstack/spec/shared';
const limit: RateLimitConfig = RateLimitConfigSchema.parse({
enabled: true,
windowMs: 60_000, // time window in milliseconds
maxRequests: 100, // max requests per window
});
認証プロバイダー
プロバイダーとログインの契約は
node_modules/@objectstack/spec/src/api/auth.zod.ts にあります。AuthProvider は
'local' | 'google' | 'github' | 'microsoft' | 'ldap' | 'saml' であり、
LoginRequestSchema には type(ログイン方法)に加えて、任意の email、
username、password、provider、redirectTo が含まれます。認証フローを
実装する前に、そのファイルでセッションとトークンのレスポンス形式を確認してください。
データソース
defineDatasource、schemaMode、external 書き込みゲート、
credentialsRef についてはobjectstack-dataの rules/datasources.md を参照してください。ドライバーパッケージと
Turso Cloud/EEに関する注意事項についてはobjectstack-platformの ドライバー選択
ガイドを参照してください。driver IDの語彙は data/driver/config-registry.zod.ts にあります。
エラーエンベロープとコード台帳(ADR-0112)
error.code は2層構造です。閉じた StandardErrorCode カタログに、
各所有パッケージが api/error-code-ledger.zod.ts で登録するコードが加わります。
ApiErrorSchema.code はその和集合を検証するため、未登録のコードは
パースに失敗し、エンベロープ適合性テストに失敗し、CIにも失敗します。
この台帳の対象はフレームワークパッケージのみです。下流のリポジトリは独自の
台帳を保持し、2つのチェックを自ら組み合わせます。形状には envelopeViolations(body)、
語彙には makeApiErrorSchema(yourCodes) を使用します(どちらも
api/contract.zod.ts にあります)。どのリポジトリも、いずれの台帳にもないコードを
出力してはなりません。
ベストプラクティス
- 可能な限り自動生成されたAPIを使用してください。 CRUD + トリガーでは表現できない ビジネスロジックに限り、カスタムエンドポイントを作成してください。
- 一貫したエラー形式を返してください。 ディスパッチャーのエンベロープは
DispatcherErrorResponseSchemaです。{ success: false, error: { code, message, httpStatus?, route?, service?, hint? } }の形式で、codeは意味を表す 文字列であり、code/messageは必須です。一般的なAPIエラーにはErrorResponseSchema(errors.zod.ts)を使用します。提供されているデータルートは 代わりにフラットな{ error, code }本文を返すことに注意してください(例:CONCURRENT_UPDATE→ 409、VALIDATION_FAILED→ 400)。すべてのエラーがsuccess: falseのエンベロープで届くとは限りません。 - 最小権限の認証を適用してください。 すべてのエンドポイントで、必要な権限を 明示的に宣言してください。
- 冪等な書き込みを意図的に設計してください。 upsertルートは生成されないため、
外部連携では一意な外部IDでクエリし、作成または更新に分岐します。これらの書き込みは
POST /api/v1/data/{object}/batchでまとめてください。
よくある落とし穴
- 409 Conflict を処理しない。 生成される
PATCH /api/v1/data/{object}/:idルートでは、2 つの形式による楽観的同時実行制御が行われます。If-Matchヘッダー または JSON ボディのexpectedVersionフィールドを使います。両方が送信された場合は ボディが優先され、トークンには通常、クライアントが読み取ったupdated_atの値を 使用します。どちらも送信しない場合、チェックはスキップされます。不一致の場合は 409CONCURRENT_UPDATEが返されます。引用符で囲まれた空のエンティティタグ("")は 省略扱いではなく、400VALIDATION_FAILEDとして拒否されます。 DELETEで復元できると思い込む。 ObjectStack のDELETEは完全削除です。ごみ箱は ありません(使用されなくなったenable.trashフラグは 16.x で削除されました)。復元可能に するには、独自のソフトデリート処理ではなく、フィールドごとのtrackHistory(監査証跡) またはlifecycleのアーカイブポリシーを使用してください。
作業を検証する
*.endpoint.ts、カスタムルート、または認証プロバイダーを追加したら、完了を報告する前に
作成時のチェックを実行してください。
os validate # Zod schema + CEL predicate validation + bindings (no artifact)
# or: os build # the same gates, plus emits dist/
ルートガードと認証述語には CEL が使われます。このチェックではそれらを解析し、形式に誤りが
ある場合は実行時にガードをすり抜けさせるのではなく、該当箇所を示すメッセージとともに
ゼロ以外の終了コードを返します。スキャフォールドされたプロジェクトでは、チェックは
npm run validate です。チェックの一覧については、objectstack-platform の 作業を検証する
を参照してください。
参考資料
Zod スキーマの全一覧(各項目の説明付き)については、
references/_index.md を参照してください。各項目から
node_modules/@objectstack/spec/src/ 内の該当箇所を参照できます。フィールドの正確な
形式を確認するには、必ずソースを Read してください。プロパティ名の記憶に頼らないでください。