先月あたりにalphaバージョンが公開されたCloudFlare D1をHonoと組み合わせて使います。
Honoは今回初めて使ったのですが、かなりシンプルで使いやすく今後も使っていきたい気分になりました。
Hono v2.6.2 + CloudFlare D1(Alpha) で記事を書いています。
CloudFlare D1はAlpha版です。現在も頻繁に更新があるため、記事執筆時点と情報が異なる可能性があります。
CloudFlare WorkersとHonoをセットアップ
以下のコードで準備完了です。簡単ですね。
npx wrangler init donesample
cd donesample
npm install hono
申し訳程度にHello worldも書いてみます。
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => c.text("Hello"));
export default app;
実行は以下のコマンドで。
npm start
# curl localhost:8787
# -> Hello
D1を使う
公式のドキュメントを参考に実装します。
データベースを作成する
wranglerコマンドから作成できます。
npx wrangler d1 create myfirstdone
出力は以下です。alphaバージョンなので注意書きがあります。
🚧 D1 is currently in open alpha and is not recommended for production data and traffic.
Please report any bugs to https://github.com/cloudflare/wrangler2/issues/new/choose.
To request features, visit https://community.cloudflare.com/c/developers/d1.
To give feedback, visit https://discord.gg/cloudflaredev
✅ Successfully created DB 'myfirstdone3'!
Add the following to your wrangler.toml to connect to it from a Worker:
[[ d1_databases ]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "myfirstdone"
database_id = "fddb99d1-b44d-4334-a84e-2a67e57d59ac"
wrangler.toml
を確認するとD1データベースの定義が追加されているはずです。なければさきほどのコンソールの出力をもとに追加してください。
# ...
[[ d1_databases ]]
binding = "DB"
database_name = "myfirstdone"
database_id = "3b9c4f9b-e4d1-4176-8d44-378e97c7aa46"
データベースのセットアップ
db/schema.sql
を作成します。
DROP TABLE IF EXISTS Urls;
CREATE TABLE Urls (
ID INT,
Url TEXT,
Description TEXT,
PRIMARY KEY (`Id`)
);
INSERT INTO Urls(
ID,
Url,
Description
) VALUES
(9999999, 'https://google.com', 'Test url'),
(9999998, 'https://yahoo.co.jp', 'Test url2')
;
以下のコマンドでSQLを実行します。
wrangler d1 execute myfirstdone --local --file=./db/schema.sql
HonoからD1内のデータを取得する
Honoの公式サンプルをもとにBindingを定義します。
準備
wranglerコマンドから作成した場合は D1Database
というクラスが定義されているので、以下のように追記します。
export interface Bindings {
DB: D1Database;
}
declare global {
function getMiniflareBindings(): Bindings;
}
APIを実装
URLを記録するAPIを例に実装します。
import { Hono } from 'hono';
import { Bindings } from './bindings';
const urls = new Hono<{ Bindings: Bindings }>();
interface Url {
Id: number;
Url: string;
Description: string;
}
urls.get("/", async (ctx) => {
const env = ctx.env;
const stmt = env.DB.prepare("SELECT * from Urls");
const { results } = await stmt.all<Url>();
return ctx.json({ message: results?.map((r) => r.Url) });
});
export default urls;
Honoクラスのインスタンスを作成する際にBindingsを渡さないと、D1の各種メソッドにアクセスする際に型補完が動作しなくなるので注意です。
const urls = new Hono<{ Bindings: Bindings }>();
さきほど定義したBindingsに DB
経由で prepare
all
メソッドで結果にアクセスできます。
const stmt = env.DB.prepare("SELECT * FROM Urls");
const { results } = await stmt.all<Url>();
変数も割り当て可能です。
env.DB.prepare("SELECT * FROM Urls WHERE Id = ? AND Url = ?").bind(id, url);
all
メソッドでSQLのクエリを実行し結果を取得可能ですが、ほかにもいくつか同類のメソッドがあります。利用ケースにあわせて選択しましょう。以下がメソッド一覧です。
stmt.first( [column] )
stmt.all()
stmt.raw()
stmt.run()
db.dump()
db.exec()
db.batch()
APIルーティングを追加
以下のように追加します。簡単で良いですね。
import { Hono } from 'hono';
import urls from './urls';
import { Bindings } from './bindings'
const app = new Hono<{ Bindings: Bindings }>();
app.route("/urls", urls);
export default app;
APIの動作確認
以下のコマンドで開発環境を起動します。
npx wrangler dev --local --persist
起動後、以下のコマンドを実行して開発環境のデータベースをセットアップします。
wrangler d1 execute myfirstdone --file=./db/schema.sql
APIを実行します。
curl -i http://localhost:8787/urls
# -> {"message":["https://google.com","https://yahoo.co.jp"]}
デプロイ
デプロイはとても簡単です。
npx wrangler publish
DBの初期化などクエリの実行も開発環境とほぼ同じです。
wrangler d1 execute myfirstdone --file=./db/schema.sql
DBのマイグレーション
なんとマイグレーション機能もwranglerコマンドに実装されていました。
以下のコマンドを実行すると migrations
ディレクトリが作成されて、 0000_hoge.sql
というファイルが作成されます。
wrangler d1 migrations create myfirstdone hoge
実行後のSQLファイルの中身は以下です。
-- Migration number: 0000 2022-12-18T08:10:32.404Z
SQLファイルを良い感じに書き換えてから以下のコマンドで、マイグレーションを実行します。差分管理もしてくれるので、最後に適用したマイグレーション以降を実行してくれます。実行履歴はDB側に記録している?
wrangler d1 migrations apply --local myfirstdone
便利な機能
任意のSQLクエリを実行する
以下のコマンドで任意のSQLを実行可能です。 --local
フラグの有無で実行先も簡単に切り替えられるので気軽に実行できてしまいます。
wrangler d1 execute myfirstdone --local --command='SELECT * FROM Urls'
DBのバックアップ
以下のコマンドでバックアップも作成可能です。定期的にCloudFlare側で実行されるバックアップもあります。
wrangler d1 backup create myfirstdone
最後に
まだalpha版ということですが現状でも全然使いやすい感じで開発体験も良かったです。 wrangler d1
コマンドも結構整備されていて、標準的なオペレーションは一通りできそうで個人的にはポイント高かったです。
alpha版ということによる制限もありますが、これが正式リリース後どのくらい緩和されるのかが楽しみです。データベースの容量制限なんかは特に気になります。あとはお値段。
異なるリージョンからアクセスがあったときのデータ同期も検証したかったのですが、とりあえず記事にしたかったのでまた後日。データベースの外に露出させるインタフェースは読み取り専用、という運用ならだいぶ良い感じに運用できるかもしれません。