コンテンツにスキップ

@kozou/api REST レイヤー

@kozou/api は Kozou 自前の REST レイヤーであり、v1.0 以降のデフォルト バックエンド です。他のあらゆるサーフェスを駆動するのと同じ Schema Context — あなたの CREATE TABLECREATE VIEWCOMMENT ON 文から構築されたもの — を与えると、手書きのルートコードなしで、 データベースのテーブルとビューを REST API として提供します。

このページでは、@kozou/api とは何でなぜ存在するのか、kozou dev の下で どう起動するか (および外部 PostgREST へのオプトアウト方法)、生成される エンドポイントの形、あなたの COMMENT テキストから導出される OpenAPI ドキュメント、そして引かれるセキュリティ境界について説明します。 Kozou の出力群の中で REST がどこに位置するかについては、 3 つのサーフェス を参照してください。 説明文の背後にあるタグ文法については、 COMMENT 規約 を参照してください。

それ以前の Kozou リリースでは、外部の PostgREST コンテナを配線して REST を 提供し、Admin UI はプラガブルなデータアダプター経由でそれと通信していました。 @kozou/api はその外部コンテナを Kozou 自身が所有するコードで置き換えます。 すなわち、CRUD エンドポイントと OpenAPI ドキュメントを Schema Context から 直接生成し、PostgreSQL 自体をクエリします。v1.0 以降はこれがデフォルトです — kozou dev はこれをインプロセスで起動し、PostgREST はオプトアウトになりました (下記の 起動方法 を参照)。

Admin UI は、すでに PostgREST 向けに使っているのと同じデータアダプターの 継ぎ目を通じて @kozou/api に到達します。そのため、データレイヤーの 切り替えは UI コードにとって破壊的変更ではありません。同じブラウザフローが、 どちらのバックエンドに対しても変更なしで動作します。

特に目立つ動機は 2 つあります。

  • 可動部分が 1 つ減る。 @kozou/api (デフォルト) では、別個の PostgREST コンテナを実行する必要がありません。REST レイヤーは kozou dev の 残りの部分とともにインプロセスで起動します。
  • COMMENT ネイティブな OpenAPI ドキュメント。 @kozou/api は Schema Context を読み取るため、出力する OpenAPI には、あなたが COMMENT に書いた説明文、enum 値、AI ノート、ウィジェットヒントが 含まれます。下記の OpenAPI セクション を参照してください。

@kozou/apikozou dev のデフォルトバックエンドです。 追加の設定なしで、kozou dev@kozou/api を通じて REST をインプロセスで 提供します — PostgREST コンテナは不要です。

Terminal window
# Default: Admin UI + MCP, REST served in-process by @kozou/api
kozou dev

kozou dev は 1 つのコマンドで 3 つのサーフェスを起動します。

サーフェスデフォルトポート備考
Admin UI3333生成された SvelteKit アプリ (@kozou/svelte-ui)
MCP HTTP3334AI エージェント向けの MCP サーバー (@kozou/mcp)
@kozou/api3335自前の REST レイヤー、127.0.0.1 にバインド

Admin UI のサーバーサイドフェッチは (インプロセスの) @kozou/api に到達し、 @kozou/api が PostgreSQL に直接 SQL を発行します。

代わりに外部 PostgREST を使うには、kozou.config.yamladapter.type: postgrest を設定するか (そして PostgREST サービスを追加します — スキャフォールドされた docker-compose.yml に例があります)、単発の実行に対して --adapter postgrest で上書きします。

Terminal window
# Opt out of the in-house backend for one run
kozou dev --adapter postgrest

PostgREST を選択すると、Admin UI のサーバーサイドフェッチは、同じデータ アダプターの継ぎ目を通じて、代わりに PostgREST コンテナに到達します。

フラグデフォルト説明
--adapter <kind>api (adapter.type から)REST バックエンド: api (自前、デフォルト) または postgrest (外部オプトアウト)。単発の実行に対して adapter.type 設定フィールドを上書きします。
--api-port <n>3335@kozou/api サーバーのポート (バックエンドが api のときに使用)。
Terminal window
# Move the @kozou/api port off 3335
kozou dev --api-port 4000

kozou dev のオプション一式については dev コマンド の ページを、それが読む adapter.type 設定フィールドについては kozou.config.yaml を参照してください。

@kozou/api は、Schema Context 内の各テーブルとビューから、実行時に エンドポイントを生成します。以下の例では、汎用的な products テーブル (status カラムが draft / published / archived に制約されている) と orders テーブルを使います。ご自身のリソース名に置き換えてください。

例ではデフォルトポートを前提とします。

Terminal window
B=http://127.0.0.1:3335

GET / はサービス情報と利用可能なリソースの一覧を返します。

Terminal window
curl -s "$B/" | jq

一覧 — ページネーション、ソート、検索、フィルター

Section titled “一覧 — ページネーション、ソート、検索、フィルター”

GET /<resource> はテーブルまたはビューの行を一覧します。以下をサポートします。

  • ページネーション用の page (1 始まり) と pageSize
  • 並び替え用の sort=field.asc,other.desc (複数キー可)、
  • テキストカラム横断のフリーテキスト ILIKE 用の search=<text>
  • 等価フィルター用の <column>=<value>

{ rows, total, page, pageSize } を返します。

Terminal window
# Published products, newest first, 20 per page
curl -s "$B/products?page=1&pageSize=20&sort=created_at.desc&status=published" | jq
# Free-text search across text columns
curl -s "$B/products?search=keyboard" | jq

フリーテキストの search はテキスト型のカラムを対象とします。 uuid カラムは対象から除外されます。PostgreSQL には uuid ILIKE text の演算子が存在しないためです。

GET /<resource>/<id> は、主キーによって 1 つの行を取得します。 その行、または 404 を返します。

Terminal window
curl -s "$B/products/42" | jq

アイテムルート (取得、更新、削除) は主キーで行を指定するため、主キーを 持つテーブルが必要です。複合 主キーを持つテーブルは、キーが宣言する 順序でキー成分をカンマで結合して指定します。

Terminal window
# Composite key (tenant_id, id) = (7, 42)
curl -s "$B/order_lines/7,42" | jq

主キーを 持たない リソース — ビュー、または主キーのないテーブル — には アイテムルートがなく、一覧エンドポイントのみが利用できます。(複合キーの 自体はカンマを含めません。パスセグメントは URL デコード後にカンマで 分割されます。)

POST /<resource> は JSON ボディから行を作成し、201 と作成された行を 返します。PostgreSQL が自前で供給できるカラム (DEFAULT、サーバー生成値) は省略できます。空のボディは、カラムのデフォルト値からなる行を挿入します。

Terminal window
curl -s -X POST "$B/products" \
-H 'content-type: application/json' \
-d '{"name":"Mechanical keyboard","status":"draft"}' | jq

PATCH /<resource>/<id> は指定されたカラムを更新し、更新後の行、または 404 を返します。

Terminal window
curl -s -X PATCH "$B/products/42" \
-H 'content-type: application/json' \
-d '{"status":"published"}' | jq

DELETE /<resource>/<id> は主キーによって削除し、削除された行、または 404 を返します。

Terminal window
curl -s -X DELETE "$B/products/42" | jq

リレーション選択 — as=options 形式

Section titled “リレーション選択 — as=options 形式”

リレーションピッカーを埋めるために、@kozou/api は、行全体の代わりに { id, label } ペアだけを返す軽量なルックアップを提供します。

GET /<resource>?as=options&label=<col>&fields=<a,b>&q=<text>&limit=<n>
  • label — 各オプションの表示ラベルとして使うカラム。
  • fields — 検索対象に追加するカラム。
  • q — フリーテキストクエリ (ILIKE でマッチ)。
  • limit — 返すオプションの最大数。

{ options: [{ id, label }] } を返します。

Terminal window
# Options for an orders form's "product" foreign key
curl -s "$B/products?as=options&label=name&fields=name,sku&q=key&limit=20" | jq

これは、外部キーのコンボボックスに入力したときに Admin UI が使う リレーション検索に対応します。

  • ビューは読み取り専用です。 CREATE VIEW は一覧エンドポイントとして のみ公開されます — ビューは主キーを持たないため、アイテムルートはありません。 ビューへの書き込みは 405 を返します。
  • 未知のカラムは拒否されます。 テーブルに存在しないカラムを指定した 作成または更新ボディは 400 を返します。
  • 未知のリソース404 を返します。

RPC アクション — POST /rpc/<schema>.<fn>

Section titled “RPC アクション — POST /rpc/<schema>.<fn>”

上記のテーブル・ビューの CRUD に加えて、v1.4 以降、@kozou/api は スキーマの動詞もコンパイルします。COMMENT@expose: rpc タグを 持つ Postgres 関数は、POST /rpc/<schema>.<fn> で呼び出せるアクションになり、 引数は JSON ボディから取られます。同じアクションは同時にあらゆる場所で 表面化します — ここでの REST、OpenAPI ドキュメント、 MCP の describe_functions ツール、そして Admin UI の「Actions」ページです。

Terminal window
# approve_order(order_id uuid) アクションを実行
curl -s -X POST "$B/rpc/public.approve_order" \
-H 'content-type: application/json' \
-d '{"order_id":"…"}' | jq

公開はオプトインであり、暗黙のうちに行われることはありません。呼び出し元が 実際にアクションを実行できるかどうかは、リクエストのロールにおける PostgreSQL の EXECUTE 権限で強制されます。RPC のワイヤーシェイプは Kozou v1.6 時点で 安定した契約で、テーブル・ビューの CRUD サーフェス (v1.0 以来安定) と同様です。詳しい ルールは RPC アクション を参照してください。

/openapi.json の OpenAPI ドキュメント

Section titled “/openapi.json の OpenAPI ドキュメント”

GET /openapi.json は API 全体に対する OpenAPI 3.1 ドキュメントを返します。 これを特別なものにしているのは、その説明文があなたのデータベースの COMMENT テキストから来ているという点です。これが、自前レイヤーを 際立たせる COMMENT ネイティブな OpenAPI です。

Terminal window
# The document version and the schema component names
curl -s "$B/openapi.json" | jq '.openapi, (.components.schemas | keys)'
# One table's schema (description, x-kozou-ai, enum, x-kozou-widget)
curl -s "$B/openapi.json" | jq '.components.schemas["public.products"]'

Schema Context からドキュメントへのマッピングは次のとおりです。

  • テーブル、ビュー、カラムの説明 (COMMENT の散文本体) はスキーマの description になります。
  • @ai ノートx-kozou-ai 拡張になります。
  • CHECK リストと ENUM メンバーenum になります。
  • 解決済みのウィジェット は、JSON Schema の type / format と並んで x-kozou-widget 拡張になります。

NULL 許容のカラムは型のユニオンとして出力されます — 例えば ["string", "null"] です。主キーを持つテーブルには一覧、作成、取得、更新、 削除のパスが付き、主キーを持たないテーブルには一覧と作成のみ (アイテム ルートなし)、ビューには読み取り専用の一覧パスが付きます。

次のように書かれた products の status カラムは、

COMMENT ON COLUMN products.status IS
'Publication state of the product.
@ai: Only ''published'' rows should appear in public listings.
@widget: enum-select';

ドキュメント内では、“Publication state of the product.” という descriptiondraft / published / archivedenum (カラムの CHECK リストから)、@ai テキストを運ぶ x-kozou-ai ノート、 そして enum-selectx-kozou-widget として現れます。完全なタグ文法 — @ai@widget@policy@example — については、 COMMENT 規約 を参照してください。

@policy テキストは @kozou/core によってパースされ、OpenAPI ドキュメント には x-kozou-policy 拡張 (テーブル/ビューおよびカラムのスキーマ上) として 表出されます。これは AI エージェントとクライアント向けの advisory な メタデータであり、@kozou/api はこれを強制しません。アクセス制御は あなたの PostgreSQL の行レベルセキュリティの仕事です。下記の セキュリティ境界 を参照してください。

@kozou/apiデフォルトでループバック上のゼロ認証 で動作し、設定すると opt-in の JWT + RLS レイヤーが加わります。そのデフォルトは、信頼された境界 — ローカル開発、またはプライベートな compose ネットワーク — 向けに作られています。

  • デフォルトでループバック。 サーバーは 127.0.0.1 にバインドします。 kozou dev 経由で実行する場合、同じホスト上の Admin UI の サーバーサイドフェッチからのみ到達されます。サーバーが非ループバックの ホストにバインドされた場合は、目立つ警告が出力されます。
  • 設定しない限りゼロ認証。 auth 設定がなければ、認証レイヤーは ありません — 信頼された境界を越えて公開しないでください。

実行場所にかかわらず成り立つ安全性の特性が 2 つあります。

  • 識別子の許可リスト化。 テーブル、ビュー、カラムの識別子は、クエリが 構築される前に、イントロスペクションされた Schema Context — 許可リスト — に対して検証され、防御的にクオートされます。
  • パラメータ化された値。 ユーザー提供のすべての値はパラメータ化された クエリ引数として渡されます。値が SQL テキストに補間されることはありません。

auth 設定を渡すと (kozou.config.yaml を参照)、@kozou/api は各リクエストの署名付き JWT (HS256 / RS256 / リモート JWKS) を検証し、そのリクエストを request.jwt.claims 経由で公開される claim とともに SET LOCAL ROLE <claim の role> の下のトランザクション内で実行します。 そして、あなたの PostgreSQL の行レベルセキュリティ (RLS) ポリシー が、 各リクエストが何を読み書きできるかを決めます。token のないリクエストは、 匿名ロール (anonRole) を設定していない限り 401 で拒否されます。設定して いる場合は、空の claim でそのロールの下で実行されます。存在するが無効な token は常に 401 です。

Kozou は token を検証して role を切り替えるだけで、identity の発行 (ユーザー登録・ログイン・トークン発行) は外部プロバイダに委譲します — 認証と認可 を参照してください。

  • 3 つのサーフェス — REST API が Admin UI と MCP コンテキストとどう並ぶか。
  • COMMENT 規約 — OpenAPI の説明文を 形づくる @ai@widget@policy@example タグ。
  • dev コマンド--adapter を含む、kozou dev のオプション一式。
  • kozou.config.yaml — バックエンドが 読む adapterauth の設定。