D1 はローカル開発をフル機能でサポートしており、Cloudflare がグローバルに運用しているものと同じバージョンの D1 が動きます。ローカル開発では、Workers のコマンドラインインターフェイスである Wrangler を使って、セッションと状態を管理します。
ローカル開発セッションは、本番の D1 環境を再現したスタンドアロンのローカル専用環境を作ります。本番へデプロイする 前に Worker と D1 をテストできます。
既存の D1 バインディング DB は、ローカル実行時にも Worker から使えます。
ローカル開発セッションを開始する手順は次のとおりです。
-
wrangler v3.0 以降を使っていることを確認します。
wrangler --version⛅️ wrangler 3.0.0 -
ローカル開発セッションを開始します。
wrangler dev------------------ wrangler dev now uses local mode by default, powered by 🔥 Miniflare and 👷 workerd. To run an edge preview session for your Worker, use wrangler dev --remote Your worker has access to the following bindings: - D1 Databases: - DB: test-db (c020574a-5623-407b-be0c-cd192bab9545) ⎔ Starting local server... [mf:inf] Ready on http://127.0.0.1:8787/ [b] open a browser, [d] open Devtools, [l] turn off local mode, [c] clear console, [x] to exit
この例では、Worker はローカル専用の D1 データベースにアクセスできます。Wrangler 設定ファイル の対応する D1 バインディングは、次のようになります。
{
"d1_databases": [
{
"binding": "DB",
"database_name": "test-db",
"database_id": "c020574a-5623-407b-be0c-cd192bab9545"
}
]
}[[d1_databases]]
binding = "DB"
database_name = "test-db"
database_id = "c020574a-5623-407b-be0c-cd192bab9545"wrangler dev はローカルデータと本番(リモート)データを分けます。ローカルセッションから本番データには、デフォルトではアクセスできません。本番(リモート)データベースにアクセスするには、D1 バインディングの設定で "remote" : true を指定します。詳細は リモートバインディングのドキュメント を参照してください。リモートデータベースに対して行った変更は取り消せません。
ローカル開発セッションの設定方法について、詳しくは wrangler dev のドキュメント を参照してください。
Cloudflare Pages で D1 を使う場合、ローカル専用の D1 データベースに対してのみ開発できます。Pages プロジェクトのルートに最小限の Wrangler 設定ファイル を置きます。スキーマの作成、シードデータの投入、アプリケーションロジックを増やさずに D1 を直接管理したいときに便利です。
Wrangler 設定ファイル は次のようになります。
{
// If you are only using Pages + D1, you only need the below in your Wrangler config file to interact with D1 locally.
"d1_databases": [
{
"binding": "DB", // Should match preview_database_id
"database_name": "YOUR_DATABASE_NAME",
"database_id": "the-id-of-your-D1-database-goes-here", // wrangler d1 info YOUR_DATABASE_NAME
"preview_database_id": "DB" // Required for Pages local development
}
]
}[[d1_databases]]
binding = "DB"
database_name = "YOUR_DATABASE_NAME"
database_id = "the-id-of-your-D1-database-goes-here"
preview_database_id = "DB"--local フラグを wrangler に渡すと、ローカル開発の一環としてローカルデータベースへクエリの実行やマイグレーションを行えます。
wrangler d1 execute YOUR_DATABASE_NAME \
--local --command "CREATE TABLE IF NOT EXISTS users ( user_id INTEGER PRIMARY KEY, email_address TEXT, created_at INTEGER, deleted INTEGER, settings TEXT);"上記のコマンドは、D1 データベースの ローカル専用 のバージョンに対してクエリを実行します。--local フラグがない場合、コマンドは Cloudflare のネットワーク上で動いているリモートの D1 データベースに対して実行されます。
wrangler dev --persist-to=/path/to/file を使うと、特定の場所にデータを永続化できます。チームで同じコピーを共有するとき、CI/CD で同じ初期状態を保証するとき、マシン間の移行でデータを残すときに便利です。
wrangler 2.x を使っている場合は --persist フラグが必要です。以前のバージョンでは、データはデフォルトで永続化されませんでした。
Miniflare ↗ は、本番と同じランタイムとコードで Workers や D1 などのリソースをシミュレートできます。
Miniflare の D1 サポート ↗ を使って、テスト用の D1 データベースを作成できます。
{
"d1_databases": [
{
"binding": "DB",
"database_name": "test-db",
"database_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
]
}[[d1_databases]]
binding = "DB"
database_name = "test-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"const mf = new Miniflare({
d1Databases: {
DB: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
},
});getD1Database() メソッドでシミュレートしたデータベースを取得し、本番の D1 データベースと同じようにクエリを実行できます。
const db = await mf.getD1Database("DB");
const stmt = db.prepare("SELECT name, age FROM users LIMIT 3");
const { results } = await stmt.run();
console.log(results);Wrangler は unstable_dev() を公開しており、Workers と D1 のテスト用にローカル HTTP サーバーを起動できます。Wrangler 設定で preview_database_id を指定すると、ローカルデータベースに マイグレーション を適用できます。
次の Wrangler 設定があるとします。
{
"d1_databases": [
{
"binding": "DB", // i.e. if you set this to "DB", it will be available in your Worker at `env.DB`
"database_name": "your-database", // the name of your D1 database, set when created
"database_id": "<UUID>", // The unique ID of your D1 database, returned when you create your database or run `
"preview_database_id": "local-test-db" // A user-defined ID for your local test database.
}
]
}[[d1_databases]]
binding = "DB"
database_name = "your-database"
database_id = "<UUID>"
preview_database_id = "local-test-db"CI/CD の一環として、wrangler に --local フラグを渡すとマイグレーションをローカルで実行できます。
wrangler d1 migrations apply your-database --local次の例は、Wrangler の unstable_dev() API を使って次のことを行います。
preview_database_idで定義したローカルテストデータベースにマイグレーションを適用します。- Worker で定義したエンドポイントにリクエストします。この例では
/api/users/?limit=2を使います。 - 戻り値が一致することを検証します。
Response.statusと API が返す JSON を含みます。
import { unstable_dev } from "wrangler";
import type { UnstableDevWorker } from "wrangler";
describe("Test D1 Worker endpoint", () => {
let worker: UnstableDevWorker;
beforeAll(async () => {
// Optional: Run any migrations to set up your `--local` database
// By default, this will default to the preview_database_id
execSync(`NO_D1_WARNING=true wrangler d1 migrations apply db --local`);
worker = await unstable_dev("src/index.ts", {
experimental: { disableExperimentalWarning: true },
});
});
afterAll(async () => {
await worker.stop();
});
it("should return an array of users", async () => {
// Our expected results
const expectedResults = `{"results": [{"user_id": 1234, "email": "[email protected]"},{"user_id": 6789, "email": "[email protected]"}]}`;
// Pass an optional URL to fetch to trigger any routing within your Worker
const resp = await worker.fetch("/api/users/?limit=2");
if (resp) {
// https://jestjs.io/docs/expect#tobevalue
expect(resp.status).toBe(200);
const data = await resp.json();
// https://jestjs.io/docs/expect#tomatchobjectobject
expect(data).toMatchObject(expectedResults);
}
});
});テスト内での API の使い方について、詳しくは unstable_dev() のドキュメントを参照してください。
wrangler devで Worker と D1 をローカル実行し、デプロイ前に問題をデバッグします。- D1 のデバッグ方法 を確認します。
- Worker と D1 が出力する ログへのアクセス方法 を理解します。