hono, prisma, zod, cloudflare

Naoki Tomita Naoki Tomita December 26th, 2025 life typescript

今年はプログラマーの仕事はぐっと減らし、リモートで週2,3日稼働で可能な範囲で受けています。ちょうどfluct時代にお世話になったもっちーさんが独立してさっそく困っているということで、お手伝いをしてました。【PR】もっちーさんはお手伝いを募集中!

その後1年ほどやってみての所感を放流しておきます。

Cloudflare

Cloudflareは以前から好き。SimpleというよりEasyなのだがよくできてる。めんつゆ最高。謎のテクノロジーでsqliteがエッジで動く

DuckDBを使いたくて(Betaの)Cloudflare Containers使ったが、npm run dev から裏でdocker build/runが走ってすんなり使え、「おお、wrangler.jsoncにBindingを記述したらコンテナがDIされてきた」と感心した。1

Hono

yusukebe氏ががんばってる流行りのフレームワーク。さすが困ることなく使える😀

OpenAPI定義をどちらでやるか

@hono/zod-openapihono-openapi を使う2パターンがあって名前も似てて検索結果も混じりやすい。標準honoのapi2 に乗っかる方が好みなので、middleware提供スタイルであるhono-openapiの方を利用した。とはいえ、実ハンドラーコードの前にどっかりopenapiの定義、その後どっかりzodの定義が重なるので見通しは微妙。

CIでopenapi.jsonを生成するのを入れてたが、ある時なぜかdescribeRoute()の記述が取れないハンドラーがあった。調べたら「onError()定義があるsub app」で起きるエッジケースだったようなので、PRを送った。※merge済

Prisma

型とスキーマ管理が欲しいし有名だから選択したけど…。若干後悔している。ORMはやっぱ自分の足元を撃ちますな。kyselyとかの方が良かったかなあ

現在、最新版がブロッカーになっていて辛い。あとバージョンあげるにしても、prisma, zod, hono-openapi, honoあたりまとめて。かつ、作成されたtype/clientを共用しているfront側アプリも全部まとめて上げるがんばりが必要でダルい

prisma generator(@prisma/generator-helper)は楽しい

protobufを思い出した。今回作るのがActive RecordっぽいCRUDハンドラーばかりだったので、まるっとgenereate。jsでゴリゴリtsを書くのおもしろい。DMMF構造体がもっと(リレーションの情報とか)メタ情報が取れれば良いのだけど、モデル名・テーブル名・フィールド名だけでもけっこうやりたいことはできる

CIでのファイルの生成時(つまりcloudflare workersとかwrangler devではない環境)ではcloudflare:workers moduleが読まれると動かないので、一部遅延読み込みにするなどをして対応したがもっといいやり方があるのかもしれない

const { getContainer } = await import('@cloudflare/containers')

実際こんな感じのgenerate祭り

                 ┌─▶ D1 migrations
                 │
 schema.prisma ──┼─▶ prisma client
                 ├─▶ ERD
                 ├─▶ zod schemata / types
                 └─▶ handlers(hono) ────▶ openapi.json
                                            └─▶ api/README.md

package.jsonのscriptsでgenerateの依存順を管理するのに、npm-run-all2を使った

  "scripts": {
    ...
    "generate": "run-s generate:*",
    "generate:cf-type": "wrangler types --env-interface CloudflareBindings",
    "generate:schema-format": "prisma format",
    "generate:schema-generates": "prisma generate",
    "generate:api-openapi.json": "npx --yes tsx doc/openapi-generator.ts",
    "generate:api-readme.md": "npx --yes openapi-to-md doc/openapi.json > doc/README.md"
  },

D1 migrationをどちらでやるか

prismaを使う場合Cloudflare D1のマイグレーション管理のやり方は2パターンあるが、今回ターゲットがD1ということと、prismaのロックオンを避けたい気持ちでBのwranglerコマンドを使う方にした。

具体的には、schema.prismaをいい感じにしたあと、こんなので差分をmigrationファイルとして出力させて(必要なら微調整)

npx prisma migrate diff --from-local-d1 --to-schema-datamodel schema.prisma --script > db/migrations/0002_aaaaa.sql

ローカルで適用して確認

find .wrangler/state/v3/d1/miniflare-D1DatabaseObject/ -type f -name '*.sqlite' -delete
npx wrangler --env test d1 migrations apply test-db --local
  1. 実稼働には、暖気設定とかがほしくなりそうではある。batchで暖気を入れている 

  2. honoのapiはmiddleware/handlerが、next呼ぶか/returnするかの違いってのが綺麗なデザインだなと思うところ。