個人開発でCloudflare Workers + HonoのAPIサーバーを立てた話
個人開発しているサービスの話。フロントはSPA(Vite + React)で作りたかったけど、クライアントだけでは完結できない処理があって、Cloudflare Workers上にHonoでAPIサーバーを立てた。すごい良かった。
SPAだけでは完結しなかった理由
作っているサービスには、ユーザーに見せたくないデータや、クライアント側に任せると信頼できない判定処理がいくつかあった。Reactだけで完結させると、そういう情報やロジックをどこかのタイミングでフロントに持たせる必要が出てきて、JSやネットワークタブから漏れたり改ざんされたりするリスクが消えない。そのあたりの処理はサーバー側でやるしかなく、バックエンドが必須になった。
なぜCloudflare Workers + Honoか
フロントとAPIを別サービスに分けることも考えたけど、個人開発だと運用コストがなぁと。Cloudflare Workersはアセット配信とAPIを1つのWorkerに同居させられるのが良かった。wrangler.jsoncの assets.run_worker_first に /api/* を指定するだけで、未知のパスはSPAの index.html を返しつつ /api/* だけWorkerに処理させる、という出し分けができる。
フレームワークはHono。Cloudflare Workersがいい感じにサポートされてるだけあって軽くて速く、Expressに近い感覚でルーティングを書けるのがよき。worker/routes 配下にエンドポイントごとにファイルを分けて、index.tsでapp.routeを使ってマウントしているだけのシンプルな構成にしている。
実際に組んだもの
DBにはCloudflare D1を使い、アプリ固有のデータを保存。外部APIのプロキシと短期キャッシュはCache APIで対応。負荷がかかりやすいエンドポイントにはWorkers Rate Limiting bindingでレート制限をかけて、外部APIのリクエスト上限保護とabuse対策を両立させた。さらにCron Triggerで不要になった一時データの掃除と、D1からR2への日次バックアップも動かしている。これだけの機能を、同じWorkerとwrangler.jsoncの設定だけで完結できたのはかなり良い。良い。
エッジサーバーの魅力
使う前は「世界中どこからアクセスしても物理的な距離による遅延がない」くらいのイメージで期待していたんだけど、実際ちゃんと調べてみるとそこまで単純じゃなかった。Cloudflare Workersのコード自体はユーザーに近いエッジで実行されるので、認証チェックやマスキング処理みたいな軽い処理は確かに近くで動いてくれる。ただ自分が使っているD1は単一リージョンのDBみたいな感じなので、書き込みが絡む処理まで「世界中どこでも低遅延」というわけではなさそう。個人開発でそこまでユーザーが分散しているわけでもないので体感できてはいないけど、「エッジだから常に爆速」というのは思い違いだった。
それより実際に使ってみて大きかったのは「簡単さ」の方だった。フロントとAPIを1つのWorkerにまとめて pnpm deploy(pnpm run build && wrangler deploy) 一発でデプロイできるし、D1・R2・Cron・レート制限まで全部同じwrangler.jsoncに書くだけでバインディングされる。個人開発だとサーバーの運用やインフラの面倒くささが正直一番のボトルネックになりがち(あんま知識ないから)なんだけど、それがほぼ気にならなくなった感じがある。
使ってみた感想
ローカル開発の体験もとてもよろしい。@cloudflare/vite-plugin のおかげで、フロント・Worker・D1のローカルシミュレーションが pnpm dev 一発で立ち上がる。APIサーバーを別プロセスで起動する必要すらないのはすんごい良い。
「エッジだから世界中どこでも遅延ゼロ」みたいな過剰な期待は反省だけど、個人開発でここまでインフラを意識せずに「バックエンドが欲しい」を満たせるのは正直かなり良い。次に何か作るときも、Cloudflare Workers + Honoは結構なケースで採用しそう。脳死で Next.js やるか〜はなくなりそう。