Cloudflareとか
Honoを試す、で炎上するw
hono環境を作る。bunでやってみる。
前提としては、bun入りdevcontainer環境を事前に作成しているのでそちらから実行。
$ bun create hono
create-hono version 0.13.0
? Target directory hono-example
? Which template do you want to use? cloudflare-workers
? Do you want to install project dependencies? yes
? Which package manager do you want to use? bun
✔ Cloning the template
✔ Installing project dependencies
🎉 Copied project files
Get started with: cd hono-example
んで、動かしてみる。
$ cd hono-example
$ bun run dev
$ wrangler dev src/index.ts
⛅️ wrangler 3.75.0
-------------------
? Would you like to help improve Wrangler by sending usage metrics to Cloudflare? › (Y/n)╭─────────────────────────────────
⎔ Starting local server...
[wrangler:inf] Ready on http://localhost:8787
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ [b] open a browser, [d] open Devtools, [l] turn off local mode, [c] clear console, [x] to exit │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
こうなるんでブラウザから http://localhost:8787 へアクセスするもうまくいかず。。。
困ったらchat GPT大先生にヘルプ。
そしたら、wrangler.tomlファイルにdevの設定をしたらええそうで提案して貰った内容の
# ローカル開発時の設定
[dev]
port = 8787 # ローカルで使用するポート
ip = "127.0.0.1" # 開発用のIPアドレス (通常は127.0.0.1)
設定して保存したら、ターミナル側で勝手にリロードしてくれて表示が変わった。
wrangler.toml changed...
⎔ Reloading local server...
⎔ Reloading local server...
[wrangler:inf] Updated and 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 │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ほな、もっかい!ということでブラウザで再度、 http://localhost:8787 へアクセスしたら。。。
あかんやん!
Chat GPT大先生の嘘つき~。
ちゃんとdevcontainer環境で、ってプロンプトにも書いたのにぃ。
うーん、なんでや?
ちょっと悩んだ末、127.0.0.1 やとコンテナのローカル環境しかアクセスでけへん事に気づく。
ああ、そしたら全部受けたらええやん。
と言うことで設定を変更
# ローカル開発時の設定
[dev]
port = 8787 # ローカルで使用するポート
ip = "0.0.0.0" # 開発用のIPアドレス (コンテナへのアクセスは全部通すので0.0.0.0)
としたらまたまたターミナルに変化があった。
wrangler.toml changed...
⎔ Reloading local server...
⎔ Reloading local server...
[wrangler:inf] Updated and ready on http://0.0.0.0:8787
再々度、ブラウザから http://localhost:8787 にアクセスしてみると今度は
Hello Hono!
と表示された。
めでたしめでたし。
Cloudflare D1 devcontainer環境で試し、燃え上がるw
CloudflareにD1と言う素敵なsqlite環境があるという事で試してみたら、炎上したw
環境としてはdevcontainerにbun実行環境(nodejs)なんやけど、チュートリアルとかそのまんま動かしてもうまくいかへんかった。
前提としてはHonoの時と一緒なので、
# ローカル開発時の設定
[dev]# ローカル開発時の設定
[dev]
port = 8787 # ローカルで使用するポート
ip = "0.0.0.0" # 開発用のIPアドレス (コンテナへのアクセスは全部通すので0.0.0.0)
も前提として入れとくこと。
$ bunx wrangler d1 create sample-db
⛅️ wrangler 3.78.2
-------------------
Attempting to login via OAuth...
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=...中略...
▲ [WARNING] Failed to open
✘ [ERROR] Timed out waiting for authorization code, please try again.
✘ [ERROR] Did not login, quitting...
🪵 Logs were written to "/home/app/.config/.wrangler/logs/wrangler-2024-09-14_01-02-56_935.log"
error: "wrangler" exited with code 1
ってなるんで、リンクをコピーしてブラウザに貼り付けてログインして。。。ってやってもうまくいかへんし。。。
原因としては、OAuthの流れで行くと、リンク先はブラウザで開いて許可出したらコールバックでローカルのサーバで受けて、ってやるけど、devcontainer環境なんで受けられへん訳やね。。。
しゃーないから、再びChatGPT大先生にお出まし頂く。
ご宣託としては、APIトークンであんじょうやったったらええねんで、とのお達し。
つーことで、cloudflareのコンパネにGo!
- 右上の
ヒト型アイコン
からマイプロフィール
を選ぶ。 - 左のメニューから
APIトークン
を選び、トークンを作成する
ボタンでクリック。 - 権限のテンプレートがあるので
Cloudflare Workersを編集する
のテンプレートを使用する
ボタンをクリック。 - 次の画面でアクセス許可にD1がないので
+更に追加する
としてアカウント
とD1
編集
をドロップダウンから選ぶ - アカウントリソースで
含む
自分のアカウント名
をドロップダウンから選択 - ゾーンリソースで
含む
アカウントにある全てのゾーン
自分のアカウント名
をドロップダウンから選択 -
概要に進む
をクリックすると、確認画面へ遷移する
すると
Cloudflare Workers を編集する API トークンの概要
この API トークンは、それぞれの権限とともに、以下のアカウントとゾーンに影響します
アカウント名's Account - Workers KV Storage:編集, Workers スクリプト:編集, アカウント設定:読み取り, Workers Tail:読み取り, Workers R2 Storage:編集, Cloudflare Pages:編集, D1:編集
すべてのゾーン - Workers ルート:編集
すべてのユーザー - ユーザーの詳細:読み取り, メンバーシップ:読み取り
と設定した内容の最終確認があるのでトークンを作成する
をクリックするとトークンが作成される。
なお、トークン作成時の
- クライアント IP アドレスフィルタリング
- TTL
については本来設定すべきやけど、今回はテストなのでパス。
で、次の画面では作成されたAPIトークンが表示されるのできちんとコピーしてどっかに保存しとく。再度表示はでけへんからきちんとどっかにメモっとけ!って感じやなぁ。
で、次はそのAPIキーをdevcontainer環境上に環境変数として反映させる。
$ export CLOUDFLARE_API_TOKEN=[取得したAPIトークン文字列]
でも、このやり方、シェル起動毎に書くのもいややし、.bashrcとかに書くっていうのもプロジェクト異なる毎に書き換えになるんでいややなぁ。
てことで、プロジェクトフォルダ内の .env
に書くことで解決することにした。
CLOUDFLARE_API_TOKEN = "[取得したAPIトークン文字列]"
としてから、先ほど失敗したd1データベース作成のコマンドを再実行。
$ bun run wrangler d1 create sample-db
⛅️ wrangler 3.78.2
-------------------
✅ Successfully created DB 'sample-db' in region APAC
Created your new D1 database.
[[d1_databases]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "sample-db"
database_id = [ここに作成したデータベースのIDが表示される]
となるので、最後に表示されている内容をwrangler.tomlに追記。
[[d1_databases]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "sample-db"
database_id = [ここに作成したデータベースのIDが表示される]
確認
$ bun run wrangler d1 list
⛅️ wrangler 3.78.2
-------------------
┌──────────────────────────────────────┬─────────┬────────────┬──────────────────────────┬───────────┬────────────┐
│ uuid │ name │ version │ created_at │ file_size │ num_tables │
├──────────────────────────────────────┼─────────┼────────────┼──────────────────────────┼───────────┼────────────┤
│ XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX │sample-db│ production │ 2024-09-15T05:03:10.024Z │ │ │
└──────────────────────────────────────┴─────────┴────────────┴──────────────────────────┴───────────┴────────────┘
よしよし、データベースで来てる。
これでテーブルCREATEのSQLを実行したらいけるはず。
と言うことで、sqlファイル
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
user_name TEXT NOT NULL,
user_email TEXT NOT NULL UNIQUE,
user_phone_number TEXT NOT NULL,
user_address TEXT,
user_password TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (user_name, user_email, user_phone_number, user_address, user_password)
VALUES
('Alice Cooper', 'alice@example.com', '03-1111-2222', 'Chuo-ku, Tokyo, Japan', 'abcdefg'),
('Bob Marley', 'bob@example.com', '03-2222-2222', 'Minato-ku, Tokyo, Japan', 'abcdefg'),
('Charlie Sheen', 'charlie@example.com', '03-3333-3333', 'Toshima-ku, Tokyo, Japan', 'abcdefg');
で、実行。
$ bun run wrangler d1 execute sample-db --local --file=sql/create_table.sql
⛅️ wrangler 3.78.2
-------------------
🌀 Executing on local database todo-db ([作成したデータベースのID]) from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
つづいて、
$ bun run wrangler d1 execute sample-db --local --command='SELECT * FROM users;'
⛅️ wrangler 3.78.2
-------------------
🌀 Executing on local database todo-db (c359313a-4323-449a-98db-c4e931426c1b) from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
┌─────────┬───────────────┬─────────────────────┬───────────────────┬──────────────────────────┬───────────────┬─────────────────────┬─────────────────────┐
│ user_id │ user_name │ user_email │ user_phone_number │ user_address │ user_password │ created_at │ updated_at │
├─────────┼───────────────┼─────────────────────┼───────────────────┼──────────────────────────┼───────────────┼─────────────────────┼─────────────────────┤
│ 1 │ Alice Cooper │ alice@example.com │ 03-1111-2222 │ Chuo-ku, Tokyo, Japan │ abcdefg │ 2024-09-15 16:48:14 │ 2024-09-15 16:48:14 │
├─────────┼───────────────┼─────────────────────┼───────────────────┼──────────────────────────┼───────────────┼─────────────────────┼─────────────────────┤
│ 2 │ Bob Marley │ bob@example.com │ 03-2222-2222 │ Minato-ku, Tokyo, Japan │ abcdefg │ 2024-09-15 16:48:14 │ 2024-09-15 16:48:14 │
├─────────┼───────────────┼─────────────────────┼───────────────────┼──────────────────────────┼───────────────┼─────────────────────┼─────────────────────┤
│ 3 │ Charlie Sheen │ charlie@example.com │ 03-3333-3333 │ Toshima-ku, Tokyo, Japan │ abcdefg │ 2024-09-15 16:48:14 │ 2024-09-15 16:48:14 │
└─────────┴───────────────┴─────────────────────┴───────────────────┴──────────────────────────┴───────────────┴─────────────────────┴─────────────────────┘
よっしゃ!いけた!
prismaとclouflare d1 を連携してみる
基本的には公式のGet Startedとかをなぞってみるんやけど、既存テーブルとかあるのでその辺考えながら進めることにする。
あとは、cloudflare d1 ローカル(あとでリモート)環境なので
も確認。
Prisma ORM support for Cloudflare D1 is currently in Preview
おおぅ、現在プレビューってことか。大きく変わるかも知らんけど、とりあえずここを元にして進めることにする。
ちょっとprismaってなんやろな
- nodeJS/Typescript ORM
- 主要コンポーネント
- prisma Client
- prisma Migrate
- prisma Studio
- 基本的な流れ
- 環境構築(初回のみ)
- prismaの初期化(初回のみ)
- スキーマの定義
- マイグレーションの作成と実行
- prisma Clientの生成
- 以降はコード内で使用
基本この流れやけど、公式に書いてあるd1の注意点をまとめてみる。
cloudflare d1とprisma使う時の注意点
- 通常のdbの場合はprisma migrateとかつかって全部prismaで完結するが、d1の自前マイグレーション機能があるのでそちらを使う
-
wrangler d1 migrateions
コマンド
-
- sqliteデータベースプロバイダとともに
@prisma/adpter-d1
ドライバアダプタも必要
環境構築
で、基本的にbun環境なのでTypescript関連の手順は飛ばして、prismaインストールあたりから始める。
$ bun add -d prisma
[0.07ms] ".env"
bun add v1.1.27 (267afa29)
installed prisma@5.19.1 with binaries:
- prisma
6 packages installed [470.00ms]
$ bun add @prisma/client @prisma/adapter-d1
[0.07ms] ".env"
bun add v1.1.27 (267afa29)
installed @prisma/client@5.19.1
installed @prisma/adapter-d1@5.19.1
4 packages installed [1.65s]
prisma本体のインストールとクライアント、d1アダプタをインストールする。prisama本体はdevDependenciesでインストール。
prismaの初期設定
次にデータソースのプロバイダを sqlite
としてinitする。
$ bun run prisma init --datasource-provider sqlite
✔ Your Prisma schema was created at prisma/schema.prisma
You can now open it in your favorite editor.
warn You already have a .gitignore file. Don't forget to add `.env` in it to not commit any private information.
Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Run prisma db pull to turn your database schema into a Prisma schema.
3. Run prisma generate to generate the Prisma Client. You can then start querying your database.
4. Tip: Explore how you can extend the ORM with scalable connection pooling, global caching, and real-time database events. Read: https://pris.ly/cli/beyond-orm
More information in our documentation:
https://pris.ly/d/getting-started
プロジェクトディレクトリに prisamaが作成されて、prisma/schema.prisma ファイルが生成される。
中身を確認すると
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
となってた。
d1ドライバアダプタを利用するため修正が必要
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
+ previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
スキーマの定義
次はマイグレーション用のディレクトリとファイルを生成する。
$ bun run wrangler d1 migrations create example-db drop_user_table
⛅️ wrangler 3.78.2
-------------------
✔ No migrations folder found. Set `migrations_dir` in wrangler.toml to choose a different path.
Ok to create /app/example-todo-api/migrations? … yes
✅ Successfully created Migration '0001_drop_user_table.sql'!
The migration is available for editing here
/app/example-todo-api/migrations/0001_drop_user_table.sql
コメントだけの空のsqlファイルができる
-- Migration number: 0001 2024-09-15T17:03:39.563Z
さて、前回作ったテーブルは一旦消したい。
まだモデルを作っていないので schema.prismaには存在しない。
この状態で prisma migrate difff --from-local-d1 ...
とするとローカルDBにはテーブルが存在し、モデルが存在しないのでその差分でテーブルドロップとなる。
$ bun prisma migrate diff --from-local-d1 --to-schema-datamodel ./prisma/schema.prisma --script > migrations/0001_drop_user_table.sql
としてテーブルを削除するSQLを migrations/0001_drop_user_table.sql
に再生成。
-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "users";
PRAGMA foreign_keys=on;
できあがったマイグレーションsqlを実行
$ bun run wrangler d1 migrations apply example-db --local
⛅️ wrangler 3.78.2
-------------------
Migrations to be applied:
┌──────────────────────────┐
│ name │
├──────────────────────────┤
│ 0001_drop_user_table.sql │
└──────────────────────────┘
✔ About to apply 1 migration(s)
Your database may not be available to serve requests during the migration, continue? … yes
🌀 Executing on local database example-db ([生成されたデータベースID]) from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
┌──────────────────────────┬────────┐
│ name │ status │
├──────────────────────────┼────────┤
│ 0001_drop_user_table.sql │ ✅ │
└──────────────────────────┴────────┘
その後、 prisma/schema.prisma
にモデルを追記。
model User {
userId Int @id @default(autoincrement()) @map("user_id")
userName String @map("user_name")
userEmail String @unique @map("user_email")
userPhoneNumber String @unique @map("user_phone_number")
userAddress String? @map("user_address")
userPassword String @map("user_password")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @map("updated_at")
@@map("users")
}
テーブル名/カラム名をスネークケースにしたいのでモデル名/フィールド名に@@map/@mapで関連付けしておく。
また、emailとphoneNumberはユニーク制約を付けるため@uniqueをフィールドに付与。
マイグレーションの作成と実行
このモデルを元にマイグレーションファイルを生成する。
$ bun prisma migrate diff --from-local-d1 --to-schema-datamodel ./prisma/schema.prisma --script > migrations/0002_create_user_table.sql
できあがったマイグレーションファイル
-- CreateTable
CREATE TABLE "users" (
"user_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"user_name" TEXT NOT NULL,
"user_email" TEXT NOT NULL,
"user_phone_number" TEXT NOT NULL,
"user_address" TEXT,
"user_password" TEXT NOT NULL,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateIndex
CREATE UNIQUE INDEX "users_user_email_key" ON "users"("user_email");
-- CreateIndex
CREATE UNIQUE INDEX "users_user_phone_number_key" ON "users"("user_phone_number");
よしよし、きちんと想定通りできてるやん!
で、これをapplyするので再度実行
$ bun run wrangler d1 migrations apply example-db --local
⛅️ wrangler 3.78.2
-------------------
Migrations to be applied:
┌────────────────────────────┐
│ name │
├────────────────────────────┤
│ 0002_create_user_table.sql │
└────────────────────────────┘
✔ About to apply 1 migration(s)
Your database may not be available to serve requests during the migration, continue? … yes
🌀 Executing on local database example-db ([生成したデータベースID]) from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
┌────────────────────────────┬────────┐
│ name │ status │
├────────────────────────────┼────────┤
│ 0002_create_user_table.sql │ ✅ │
└────────────────────────────┴────────┘
後はINSERT文を作成してこれを実行
INSERT INTO users (user_name, user_email, user_phone_number, user_address, user_password)
VALUES
('Alice Cooper', 'alice@example.com', '03-1111-2222', 'Chuo-ku, Tokyo, Japan', 'abcdefg'),
('Bob Marley', 'bob@example.com', '03-2222-2222', 'Minato-ku, Tokyo, Japan', 'abcdefg'),
('Charlie Sheen', 'charlie@example.com', '03-3333-3333', 'Toshima-ku, Tokyo, Japan', 'abcdefg');
$ bun run wrangler d1 execute sample-db --local --file=sql/insert_user.sql
⛅️ wrangler 3.78.2
-------------------
🌀 Executing on local database example-db ([生成したデータベースID]) from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
$ bun run wrangler d1 execute example-db --local --command="SELECT * FROM users;"
⛅️ wrangler 3.78.2
-------------------
🌀 Executing on local database example-db ([生成したデータベースID]) from .wrangler/state/v3/d1:
🌀 To execute on your remote database, add a --remote flag to your wrangler command.
┌─────────┬───────────────┬─────────────────────┬───────────────────┬──────────────────────────┬───────────────┬─────────────────────┬─────────────────────┐
│ user_id │ user_name │ user_email │ user_phone_number │ user_address │ user_password │ created_at │ updated_at │
├─────────┼───────────────┼─────────────────────┼───────────────────┼──────────────────────────┼───────────────┼─────────────────────┼─────────────────────┤
│ 1 │ Alice Cooper │ alice@example.com │ 03-1111-2222 │ Chuo-ku, Tokyo, Japan │ abcdefg │ 2024-09-15 17:51:01 │ 2024-09-15 17:51:01 │
├─────────┼───────────────┼─────────────────────┼───────────────────┼──────────────────────────┼───────────────┼─────────────────────┼─────────────────────┤
│ 2 │ Bob Marley │ bob@example.com │ 03-2222-2222 │ Minato-ku, Tokyo, Japan │ abcdefg │ 2024-09-15 17:51:01 │ 2024-09-15 17:51:01 │
├─────────┼───────────────┼─────────────────────┼───────────────────┼──────────────────────────┼───────────────┼─────────────────────┼─────────────────────┤
│ 3 │ Charlie Sheen │ charlie@example.com │ 03-3333-3333 │ Toshima-ku, Tokyo, Japan │ abcdefg │ 2024-09-15 17:51:01 │ 2024-09-15 17:51:01 │
└─────────┴───────────────┴─────────────────────┴───────────────────┴──────────────────────────┴───────────────┴─────────────────────┴─────────────────────┘