実験的機能: @kozou/api REST レイヤー
実験的機能 (Kozou v0.2)。
@kozou/apiはまだ npm に公開されていません。 パッケージが安定化するまでの間、その API と通信フォーマットは予告なく 変更される可能性があります。v0.2 系では PostgREST が引き続きデフォルトの REST レイヤーであり、@kozou/apiは完全にオプトインです。
@kozou/api は Kozou 自前の REST レイヤーです。他のあらゆるサーフェスを
駆動するのと同じ Schema Context — あなたの CREATE TABLE、
CREATE VIEW、COMMENT ON 文から構築されたもの — を与えると、手書きの
ルートコードなしで、データベースのテーブルとビューを REST API として
提供します。これは、将来の Kozou v1.0 がデフォルトにすると見込まれている、
自前のデータレイヤーです。
このページでは、@kozou/api とは何でなぜ存在するのか、その有効化方法、
生成されるエンドポイントの形、あなたの COMMENT テキストから導出される
OpenAPI ドキュメント、そして守るべきセキュリティ境界について説明します。
Kozou の出力群の中で REST がどこに位置するかについては、
3 つのサーフェス を参照してください。
説明文の背後にあるタグ文法については、
COMMENT 規約 を参照してください。
概要と存在理由
Section titled “概要と存在理由”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/api は kozou dev のフラグによって
ゲートされています。このフラグがなければ、kozou dev は従来とまったく
同じ挙動をし、デフォルトの REST アダプター (PostgREST) を使います。
# Default: Admin UI + MCP, REST served by PostgRESTkozou dev
# Experimental: Admin UI + MCP, REST served by the in-house @kozou/apikozou dev --adapter api--adapter api を付けると、kozou dev は 1 つのコマンドで 3 つの
サーフェスを起動します。
| サーフェス | デフォルトポート | 備考 |
|---|---|---|
| Admin UI | 3333 | 生成された SvelteKit アプリ (@kozou/svelte-ui) |
| MCP HTTP | 3334 | AI エージェント向けの MCP サーバー (@kozou/mcp) |
@kozou/api | 3335 | 自前の 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 が設定されているときに使用)。 |
# Move the @kozou/api port off 3335kozou dev --adapter api --api-port 4000--adapter に api 以外の値を渡すとエラーになります。デフォルトの REST
アダプターを使うには、このフラグを完全に省略してください。kozou dev の
オプション一式については、dev コマンド のページを
参照してください。
REST エンドポイントの形
Section titled “REST エンドポイントの形”@kozou/api は、Schema Context 内の各テーブルとビューから、実行時に
エンドポイントを生成します。以下の例では、汎用的な products テーブル
(status カラムが draft / published / archived に制約されている)
と orders テーブルを使います。ご自身のリソース名に置き換えてください。
例ではデフォルトポートを前提とします。
B=http://127.0.0.1:3335サービス情報
Section titled “サービス情報”GET / はサービス情報と利用可能なリソースの一覧を返します。
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 } を返します。
# Published products, newest first, 20 per pagecurl -s "$B/products?page=1&pageSize=20&sort=created_at.desc&status=published" | jq
# Free-text search across text columnscurl -s "$B/products?search=keyboard" | jqフリーテキストの search はテキスト型のカラムを対象とします。
uuid カラムは対象から除外されます。PostgreSQL には uuid ILIKE text
の演算子が存在しないためです。
id による取得
Section titled “id による取得”GET /<resource>/<id> は、単一カラムの主キーによって 1 つのテーブル行を
取得します。その行、または 404 を返します。
curl -s "$B/products/42" | jqアイテムルート (取得、更新、削除) は 単一カラム の主キーを必要とします。
複合主キーを持つテーブルに対するリクエストは 400 を返します。
POST /<resource> は JSON ボディから行を作成し、201 と作成された行を
返します。PostgreSQL が自前で供給できるカラム (DEFAULT、サーバー生成値)
は省略できます。空のボディは、カラムのデフォルト値からなる行を挿入します。
curl -s -X POST "$B/products" \ -H 'content-type: application/json' \ -d '{"name":"Mechanical keyboard","status":"draft"}' | jqPATCH /<resource>/<id> は指定されたカラムを更新し、更新後の行、または
404 を返します。
curl -s -X PATCH "$B/products/42" \ -H 'content-type: application/json' \ -d '{"status":"published"}' | jqDELETE /<resource>/<id> は主キーによって削除し、削除された行、または
404 を返します。
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 }] } を返します。
# Options for an orders form's "product" foreign keycurl -s "$B/products?as=options&label=name&fields=name,sku&q=key&limit=20" | jqこれは、外部キーのコンボボックスに入力したときに Admin UI が使う リレーション検索に対応します。
書き込みルールとエラー
Section titled “書き込みルールとエラー”- ビューは読み取り専用です。
CREATE VIEWは一覧 (および取得) エンドポイントとしてのみ公開されます。ビューへの書き込みは405を返します。 - 未知のカラムは拒否されます。 テーブルに存在しないカラムを指定した
作成または更新ボディは
400を返します。 - 未知のリソース は
404を返します。
/openapi.json の OpenAPI ドキュメント
Section titled “/openapi.json の OpenAPI ドキュメント”GET /openapi.json は API 全体に対する OpenAPI 3.1 ドキュメントを返します。
これを特別なものにしているのは、その説明文があなたのデータベースの
COMMENT テキストから来ているという点です。これが、自前レイヤーを
際立たせる COMMENT ネイティブな OpenAPI です。
# The document version and the schema component namescurl -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.” という
description、draft / published / archived の enum
(カラムの CHECK リストから)、@ai テキストを運ぶ x-kozou-ai ノート、
そして enum-select の x-kozou-widget として現れます。完全なタグ文法 —
@ai、@widget、@policy、@example — については、
COMMENT 規約 を参照してください。
@policyテキストは@kozou/coreによってパースされますが、強制は されず、v0.2 の@kozou/apiは OpenAPI ドキュメントにそれを表出させません。 ポリシーの強制は将来の課題です。
セキュリティ境界
Section titled “セキュリティ境界”@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 を信頼された境界の内部に保ってください。
次に読むべきもの
Section titled “次に読むべきもの”- 3 つのサーフェス — REST API が Admin UI と MCP コンテキストとどう並ぶか。
- COMMENT 規約 — OpenAPI の説明文を
形づくる
@ai、@widget、@policy、@exampleタグ。 - dev コマンド —
--adapter apiを含む、kozou devのオプション一式。