メインコンテンツに移動

Database プラグイン

Database プラグイン

ベータ版 プラグイン

この プラグイン は現在ベータ版です。マイナーリリース間で API が変更される場合があります。@databricks/appkit/beta からインポートしてください。詳細は Plugin Stability Tiers を参照してください。

テーブルを config/database/schema.ts で宣言し、database() を登録すると、自動生成された HTTP CRUD とサーバーサイドのデータベースクライアントが利用できます。CRUD はデフォルトで宣言済みのすべてのテーブルに対して有効です。サーバーサイドからのアクセスは残したまま生成されるルートを制限したい場合は、api を使用してください。

アプリケーション共有アクセス

このプラグインは、デプロイされた Databricks Apps ではアプリのサービスプリンシパルを使用します。OBO はサポートせず、ユーザー単位や行単位の認可も適用されません。生成された API に到達できる呼び出し元は、公開されているすべての行に対して、削除を含む有効なすべての操作を実行できます。

アプリへのアクセスを制限し、そのサービスプリンシパルには必要最小限のデータベース権限のみを付与してください。ユーザーごとに異なる権限や行の所有者チェックが必要な場合は、該当する生成ルートを無効にし、カスタムサーバールートで認可を実装してください。アプリへのアクセス許可だけでは、行レベルの分離は実現できません。

基本的な使い方

Lakebase の設定の説明に従って、Lakebase の postgres リソースと接続用の環境変数を設定します。データベースのテーブルはあらかじめ存在し、宣言したスキーマと一致している必要があります。このプラグインがセットアップ時に行うのは接続確認のみで、テーブルの作成やマイグレーションは行いません。

Database プラグインを選択してスキャフォールディングしたアプリには空の config/database/schema.ts が含まれるため、サンプルテーブルがなくても database() を起動できます。PostgreSQL のテーブルが用意できたら、空の宣言を自分のモデルに置き換えてください。

ローカル開発では、PGUSERDATABRICKS_CLIENT_ID が設定されていない場合、PostgreSQL のユーザー名は Databricks の資格情報から解決されます。ユーザー名を明示的に設定した場合は、そちらが優先されます。

// config/database/schema.ts
import { defineSchema, id, text } from "@databricks/appkit/beta";

export const schema = defineSchema((builder) => ({
  notes: builder.table("notes", {
    id: id(),
    body: text().notNull(),
  }),
}));
// server/index.ts
import { createApp, server } from "@databricks/appkit";
import { database } from "@databricks/appkit/beta";

const AppKit = await createApp({
  plugins: [server(), database()],
});

サーバー プラグイン を有効にすると、次のエンドポイントが登録されます。

メソッドパス操作
GET/api/database/notes行の一覧取得
GET/api/database/notes/:id単一行の取得
POST/api/database/notes行の作成
PATCH/api/database/notes/:id行の更新
DELETE/api/database/notes/:id行の削除

公開された主キーを持たないテーブルでは、一覧取得と作成のみがサポートされます。upsert はサーバーコードから利用できますが、対応する HTTP ルートは生成されません。

スキーマの検出とオーバーライド

database()database({}) は同じ既定値を使用します。セットアップ時、プラグインはアプリケーションの作業ディレクトリからの相対パスで config/database/schema.ts を読み込み、名前付きエクスポート schema を取得します。このファイルは確定済みの defineSchema() の結果をエクスポートする必要があります。ファイルが存在しない、インポートに失敗する、エクスポートが不正といった場合、プラグインが接続プールを作成する前にセットアップが失敗します。空のスキーマが暗黙的に作成されることはありません。

デプロイメントには config/database/schema.ts とそのローカルインポートを必ず含めてください。プラグインは Jiti を介して TypeScript を読み込むため、素の Node 本番プロセスでも別途 TypeScript ローダーを用意する必要はありません。スキーマモジュールではテーブルの宣言のみを行い、データベースへの接続やアプリの起動は行わないでください。

異なる構成の場合や、サーバーバンドルのみを含むデプロイメントの場合は、スキーマを明示的にインポートしてプラグインに渡してください。

import { schema } from "../config/database/schema";

database({ schema });

明示的なスキーマは常に優先され、ファイル検出はスキップされます。明示的なスキーマが無効な場合は、別のファイルにフォールバックせず、セットアップが失敗します。

appkit generate-types を実行してデータベースレジストリを生成してください。このレジストリがあれば、明示的なスキーマを指定しない設定でも、テーブル名とフックのペイロードが推論されます。スキーマを明示的に指定した場合は、そのスキーマ自身のテーブル名に対して設定キーの照合も行われます。

生成される API を制限する

api を省略した場合、または true{} を指定した場合は、CRUD がすべて有効になります。制限の指定は任意です。書き込みを有効にするための個別のオプトインはありません。

// HTTPルートは生成しない。サーバーサイドクライアントは引き続き利用できる。
database({ api: false });

// すべてのテーブルに読み取り専用ルートを生成する。
database({ api: { writes: false } });

// 指定したテーブルのみ完全なCRUDを生成する。
database({ api: { tables: ["notes"] } });

// 読み取り・作成・更新は許可し、削除は許可しない。
database({
  api: { writes: { operations: ["create", "update"] } },
});

// すべてのテーブルを読み取り可能にし、書き込みはnotesのみ許可する。
database({
  api: { writes: { tables: ["notes"] } },
});
オプションデフォルト効果
schemaconfig/database/schema.ts の名前付きエクスポートスキーマの自動読み込みを上書きします
apitruefalse にすると生成されるルートをすべて無効化します
api.tables宣言されたすべてのテーブルルートを生成するテーブルを限定します
api.writestruefalse にすると読み取りルートのみを残します
api.writes.tables公開されたすべてのテーブル書き込みを受け付ける公開テーブルを限定します
api.writes.operationscreateupdatedelete有効にする書き込み操作を限定します

api.tables: [] は生成されるルートをすべて無効化します。書き込みテーブルまたは 書き込み操作のリストが空の場合、読み取りは維持され、書き込みのみが無効になります。 api.tables から除外したテーブルは、公開テーブルのリレーション経由でも含められません。 これらの制限が適用されるのは HTTP のみで、サーバーサイドクライアントやフックには適用されません。

制限を省略した場合はデフォルトが適用されます。形式が不正な制限を指定するとセットアップに失敗します。 たとえば { api: { write: false } } はエラーとなり、すべての書き込みの生成を許可するものではありません。 存在しないテーブル、重複した名前、サポートされていない操作も、プラグイン が接続プールを作成する前に セットアップの失敗となります。

従来の crudRoutes オプションは api に置き換えてください。古い名前は runtime で拒否されるため、 古いオプトアウト設定によって API が意図せず有効化されることはありません。読み取り専用の動作を維持するには、 api: { writes: false } を指定してください。

テーブル名とセットアップエラー

生成されるルート名は次の条件を満たす必要があります。

  • ASCII の英字で始まること。
  • ASCII の英字、数字、アンダースコア、ハイフンのみで構成されること。
  • 64 文字以内であること。
  • Express のルートは大文字小文字を区別しないため、大文字小文字を区別せずに一意であること。

デフォルトの API は、宣言されたすべてのテーブルを検証します。_events のようなテーブルは、 黙って除外されるのではなくセットアップが失敗します。エラーメッセージには該当するテーブル名が示され、 名前の変更、api.tables による除外、api: false によるルートの無効化のいずれかが提案されます。 除外したテーブルも、サーバーコードからは引き続き利用できます。

設定エラーの場合、サーバー側のエラーメッセージには対処に役立つ詳細が含まれます。 クライアントに返されるメッセージにはそれらの詳細は含まれません。

バリデーションとプライベート列

生成された API はリクエストボディをバリデーションし、未知のフィールドや読み取り専用の フィールドを拒否します。.private() を付けた列は、生成されたルートからは利用できません。 uuid().primaryKey().defaultRandom() などデータベース側で生成される主キーは、 HTTP の呼び出し元から指定できません。自然キーであれば作成時に指定できますが、主キーを HTTP 経由で更新することはできません。

バリデーションは認可ではありません。リクエストが有効であれば、公開されている行はどれでも 読み取りや変更ができてしまいます。それが意図するアクセスモデルでない場合は、 認可を組み込んだカスタムルートを使用してください。

ミューテーションフック

テーブルでは beforeCreateafterCreatebeforeUpdateafterUpdatebeforeUpsertafterUpsertafterDelete および beforeDelete を宣言できます。フックとミューテーションは 1 つのデータベーストランザクション内で実行されます。ctx.app.database 経由の関連する書き込みも 同じトランザクションに含まれます。ただし、他の プラグイン や外部 services 経由の書き込みまで トランザクションの対象になるわけではありません。

import { DatabaseValidationError } from "@databricks/appkit";

database({
  hooks: {
    notes: {
      beforeCreate(values) {
        if (typeof values.body === "string" && values.body.length > 5_000) {
          throw new DatabaseValidationError("Note too long", [
            { path: ["body"], message: "Must be at most 5000 characters" },
          ]);
        }
      },
    },
  },
});

before* フックは置き換え用の値を返すことができ、返された値は永続化前に再度バリデーションされます。DatabaseValidationError の場合は HTTP 422 が返され、詳細は公開カラムに関するものだけに限定されます。それ以外のフックの失敗では、詳細を含まないサーバーエラーが返されます。

フックは短く保ち、データベース処理はすべて await してください。トランザクションには 30 秒のコールバック期限、100 回までのデータベース操作という共有の上限、最大 8 段のミューテーションのネスト深度が設けられています。ネストしたフックチェーン内で同じエンティティに対する同じミューテーション操作を繰り返すことは拒否されます。また、PostgreSQL 側でも 30 秒の statement_timeout と 30 秒の idle_in_transaction_session_timeout が適用されます。

コールバック期限では、任意の JavaScript や HTTP リクエスト、その他の外部的な副作用をキャンセルできません。データベースのロールバックのセマンティクスが必要なフックには、外部的な副作用を含めないようにしてください。

APIリファレンス

Databricks Developer Hub

次のエージェント型アプリを数分でリリースする準備はできていますか?

ドキュメントを読む