コンテンツにスキップ

実験的機能: @kozou/api REST レイヤー

実験的機能 (Kozou v0.2)。 @kozou/api はまだ npm に公開されていません。 パッケージが安定化するまでの間、その API と通信フォーマットは予告なく 変更される可能性があります。v0.2 系では PostgREST が引き続きデフォルトの REST レイヤーであり、@kozou/api は完全にオプトインです。

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

このページでは、@kozou/api とは何でなぜ存在するのか、その有効化方法、 生成されるエンドポイントの形、あなたの COMMENT テキストから導出される OpenAPI ドキュメント、そして守るべきセキュリティ境界について説明します。 Kozou の出力群の中で REST がどこに位置するかについては、 3 つのサーフェス を参照してください。 説明文の背後にあるタグ文法については、 COMMENT 規約 を参照してください。

v0.1 では、Kozou は外部の PostgREST コンテナを配線して REST を提供し、 Admin UI はプラガブルなデータアダプター経由でそれと通信します。 @kozou/api はその外部コンテナを Kozou 自身が所有するコードで置き換えます。 すなわち、CRUD エンドポイントと OpenAPI ドキュメントを Schema Context から 直接生成し、PostgreSQL 自体をクエリします。

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/api は意図的に実験的なものです。これは v1.0 のデータレイヤーの プレビューであって、安定した契約ではありません。それに応じて扱ってください。

@kozou/apikozou dev のフラグによって ゲートされています。このフラグがなければ、kozou dev は従来とまったく 同じ挙動をし、デフォルトの REST アダプター (PostgREST) を使います。

Terminal window
# Default: Admin UI + MCP, REST served by PostgREST
kozou dev
# Experimental: Admin UI + MCP, REST served by the in-house @kozou/api
kozou dev --adapter api

--adapter api を付けると、kozou dev は 1 つのコマンドで 3 つの サーフェスを起動します。

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

デフォルトと比べて変わるのはデータパスだけです。Admin UI のサーバーサイド フェッチが、PostgREST コンテナの代わりに (インプロセスの) @kozou/api に 到達するようになり、@kozou/api が PostgreSQL に直接 SQL を発行します。 Admin UI 自体のコードは変更されません。

フラグデフォルト説明
--adapter api(省略時 = PostgREST)自前の @kozou/api バックエンドを使用します。サポートされる値は api のみです。
--api-port <n>3335@kozou/api サーバーのポート (--adapter api が設定されているときに使用)。
Terminal window
# Move the @kozou/api port off 3335
kozou dev --adapter api --api-port 4000

--adapterapi 以外の値を渡すとエラーになります。デフォルトの REST アダプターを使うには、このフラグを完全に省略してください。kozou dev の オプション一式については、dev コマンド のページを 参照してください。

@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

アイテムルート (取得、更新、削除) は 単一カラム の主キーを必要とします。 複合主キーを持つテーブルに対するリクエストは 400 を返します。

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 を返します。

/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 によってパースされますが、強制は されず、v0.2 の @kozou/api は OpenAPI ドキュメントにそれを表出させません。 ポリシーの強制は将来の課題です。

@kozou/api は v0.2 では 認証なし で出荷されます。信頼された境界の 内部での使用 — ローカル開発、またはプライベートな compose ネットワーク — を想定して作られており、そのデフォルトはそれを反映しています。

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

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

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

JWT 認証と PostgreSQL の行レベルセキュリティ (RLS) は将来の v1.0 の 課題であり、v0.2 の実験的レイヤーには含まれません。これらが実装されるまでは、 @kozou/api を信頼された境界の内部に保ってください。

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