Hono × Cloudflare WorkersでJSON APIを作る手順

Hono × Cloudflare WorkersでJSON APIを作る手順

※本記事にはプロモーション(広告・アフィリエイトリンク)を含みます。

Cloudflare Workers でバックエンド API を作りたいが、どのフレームワークを使えばいいか迷っている——そういう方に向けて、軽量フレームワーク Hono を使った JSON API の作り方を手順ごとに書きます。環境構築からデプロイまで、コマンドと設定値をそのまま使える形で整理しました。

Hono を選ぶ理由

Hono は Cloudflare Workers・Deno・Bun・Node.js など複数のランタイムで動く軽量 Web フレームワークです。Express のような Node.js 独自のオブジェクトではなく、Web 標準の Request / Response をベースに設計されているため、Workers 環境との相性が良いです。

主な特徴を挙げます。

  • ルーティングが高速:独自の高速ルーター実装を採用しており、多数のルートを登録しても処理速度が低下しにくい設計です
  • ミドルウェアが内蔵:CORS・認証・ロガーなどが標準パッケージに含まれており、追加インストールなしで使えます
  • 型安全:TypeScript 対応で c.req.json<T>() のように型パラメータを渡せます

Express に慣れた方であれば、ほぼ同じ書き方で移行できます。

事前準備

必要なもの:

  • Node.js 18 以上(node -v で確認)
  • Cloudflare アカウント(無料プランで動作確認できます)

Wrangler CLI はプロジェクト作成時に自動でインストールされますが、先に認証を済ませておくと後の手順がスムーズです。

npm install -g wrangler
wrangler login

wrangler login を実行するとブラウザが開き、Cloudflare アカウントへの OAuth 認証が求められます。

プロジェクトを作成する

Hono の公式テンプレートを使うと、Workers 向けの設定済みプロジェクトがすぐに生成されます。

npm create hono@latest my-api

対話式のプロンプトが起動します。テンプレートの選択肢が複数表示されますが、cloudflare-workers を選んでください。

? Which template do you want to use?
  aws-lambda
  bun
❯ cloudflare-workers
  deno
  nodejs

インストール後:

cd my-api
npm install

生成されるファイル構成は次のとおりです。

my-api/
├── src/
│   └── index.ts      # エントリーポイント
├── wrangler.toml     # Workers 設定ファイル
├── tsconfig.json
└── package.json

ルーティングと JSON レスポンスを書く

src/index.ts を開くと、最小構成の Hono アプリがすでに書かれています。ここにエンドポイントを追加します。

import { Hono } from 'hono'

const app = new Hono()

// GET / — テキストレスポンス
app.get('/', (c) => c.text('Hello Hono!'))

// GET /api/items — JSON を返す
app.get('/api/items', (c) => {
  const items = [
    { id: 1, name: 'りんご' },
    { id: 2, name: 'みかん' },
  ]
  return c.json({ items })
})

// GET /api/items/:id — パスパラメーターを受け取る
app.get('/api/items/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id, name: 'サンプル' })
})

// POST /api/items — リクエストボディを受け取る
app.post('/api/items', async (c) => {
  const body = await c.req.json<{ name: string }>()
  return c.json({ created: body.name }, 201)
})

// 存在しないルートへの 404
app.notFound((c) => c.json({ error: 'Not Found' }, 404))

export default app

いくつかポイントを補足します。

  • c.json(data, statusCode) で JSON レスポンスを返します。ステータスコードを省略すると 200 になります
  • c.req.param('id') でパスパラメーターを取得できます
  • c.req.json<T>() でリクエストボディを JSON としてパースします。ボディが有効な JSON 形式でない場合はパースエラーになります
  • export default app が必須です。Workers はデフォルトエクスポートを fetch ハンドラとして扱います

ローカル確認と CORS 設定

npm run dev でローカルサーバーが起動します。

npm run dev
# → http://localhost:8787 で確認できます

別ターミナルで curl を叩いて動作を確認します。

curl http://localhost:8787/api/items
# → {"items":[{"id":1,"name":"りんご"},{"id":2,"name":"みかん"}]}

curl -X POST http://localhost:8787/api/items \
  -H "Content-Type: application/json" \
  -d '{"name":"ぶどう"}'
# → {"created":"ぶどう"}

フロントエンドから API を叩く場合は CORS の設定が必要です。Hono は CORS ミドルウェアを内蔵しています。

import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'

const app = new Hono()

// 全ルートにリクエストログを出力
app.use('*', logger())

// /api/* にだけ CORS を適用
app.use('/api/*', cors({
  origin: ['https://example.com', 'http://localhost:3000'],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
}))

// ...ルート定義
export default app

origin に '*' を渡すと全オリジンを許可しますが、本番では発信元ドメインを明示するほうが安全です。allowMethods に指定しないメソッドへのプリフライトリクエストには適切な CORS ヘッダーが返されず、ブラウザ側でブロックされます。

wrangler.toml の設定とデプロイ

wrangler.toml は Workers 全体の設定ファイルです。テンプレートで自動生成されますが、確認しておくべき項目があります。

name = "my-api"
main = "src/index.ts"
compatibility_date = "2025-01-01"  # 執筆時点の例。最新の推奨値は公式ドキュメントで確認してください

# 環境変数(値をそのまま書く。シークレットは wrangler secret put で別途設定)
[vars]
ENVIRONMENT = "production"

# KV Namespace を使う場合の例
# [[kv_namespaces]]
# binding = "MY_KV"
# id = "xxxxxx"

# D1 データベースを使う場合の例
# [[d1_databases]]
# binding = "DB"
# database_name = "my-db"
# database_id = "xxxxxx"

compatibility_date は Workers API の互換性バージョンを指定します。古い日付のままにすると最新の API が使えないことがあるため、新規プロジェクトではなるべく新しい日付を使います。

シークレット(API キーなど機密情報)はファイルに書かず、wrangler secret put で登録します。

wrangler secret put MY_SECRET
# 対話式でシークレット値を入力できます

デプロイは 1 コマンドです。

wrangler deploy

成功すると https://my-api.<accountname>.workers.dev のような URL が発行されます。カスタムドメインを使いたい場合は Cloudflare ダッシュボードの Workers 設定から追加できます。

よく使うコマンドをまとめます。

操作 コマンド
ローカル起動 npm run dev
本番デプロイ wrangler deploy
リアルタイムログ確認 wrangler tail
シークレット登録 wrangler secret put SECRET_NAME

静的フロントエンドを Cloudflare Pages で配信して、この Workers API と組み合わせる構成もよく使われます。Pages のデプロイ手順は Cloudflare Pagesに静的サイトを無料でデプロイする手順 にまとめています。

まとめ

Hono + Cloudflare Workers で JSON API を作る手順を整理します。

  1. wrangler login で Cloudflare に認証する
  2. npm create hono@latest でプロジェクトを生成し、cloudflare-workers テンプレートを選ぶ
  3. src/index.ts にルートを書く
  4. npm run dev でローカル確認する
  5. wrangler deploy でエッジにデプロイする

次のステップとして、D1(Cloudflare のマネージドな SQLite 互換データベース)を Binding として繋ぐと、Workers だけでデータの読み書きまで完結する API を作れます。まずは wrangler deploy まで動かし、自分のユースケースに合わせて拡張していくのがおすすめです。

よくある質問

Cloudflare Workersの無料枠はどのくらいですか?

公式ドキュメントによると、無料プランでは1日あたり10万リクエスト、CPU時間は1リクエストあたり10msが上限です(執筆時点)。個人の検証や小規模なAPIであれば無料枠で動かせます。大量トラフィックには有料のWorkers Paidプランの検討が必要です。

HonoはCloudflare Workers以外のランタイムでも使えますか?

はい、HonoはCloudflare WorkersのほかにDeno・Bun・Node.js・Fastly Computeでも動作します。Web標準のRequest/Responseをベースに設計されているため、ランタイムを切り替えてもコードの大部分を再利用できます。

wrangler devでローカル起動すると本番と同じ挙動になりますか?

ほぼ同等ですが完全同一ではありません。KVやD1のローカルシミュレーションはwranglerが提供しますが、一部の挙動や制限値は本番Workers環境と異なる場合があります。最終確認はwrangler deploy後の本番環境で行うことを推奨します。