第4章: Hono × Workers で作る爆速型安全API(実践チュートリアル)
本章では、軽量・Web標準準拠のフレームワーク Hono と Cloudflare Workers を組み合わせ、認証付き・型安全なREST APIをゼロから構築して世界へデプロイするハンズオンを実施します。
本チュートリアルで作成するもの
- API機能:
GET /api/health(ヘルスチェック)GET /api/todos(一覧取得)POST /api/todos(Zodによるスキーマ検証付き作成)DELETE /api/todos/:id(削除)
- セキュリティ:
- APIシークレットキーによるBearerトークン認証ミドルウェア
- DX(開発者体験):
wrangler typesによる環境変数の完全型補完.dev.varsとwrangler secretの使い分け
【ハンズオンの流れ】[Step 1] C3でプロジェクト作成 ↓[Step 2] Zod バリデーションライブラリの追加 ↓[Step 3] 設定ファイル(wrangler.jsonc)の編集 ↓[Step 4] wrangler types で型定義を自動生成 ↓[Step 5] Hono APIコードの実装 ↓[Step 6] ローカルシークレット(.dev.vars)の作成 ↓[Step 7] wrangler dev と curl での動作検証 ↓[Step 8] 本番シークレット登録と世界へのデプロイStep 1: C3(create-cloudflare)でプロジェクト作成
ターミナルを開き、以下のコマンドを実行します。
npm create cloudflare@latest my-hono-api -- --framework=hono対話プロンプトが表示されたら、以下のように選択します。
╭ Create an application with Cloudflare│◇ In which directory that's not already in use?│ my-hono-api│◇ Which type of application do you want to create?│ "Hello World" Worker (Hono)│◇ Do you want to use TypeScript?│ Yes│◇ Do you want to use git for version control?│ Yes│◇ Do you want to deploy your application now?│ No (後ほど設定・テストしてからデプロイします)作成されたディレクトリに移動します。
cd my-hono-api生成されたディレクトリ構造
my-hono-api/├── .gitignore├── package.json├── tsconfig.json├── wrangler.jsonc # Cloudflare Workersの設定ファイル└── src/ └── index.ts # APIのエントリーポイントStep 2: バリデーションライブラリの追加
リクエストボディの型チェックとサニタイズを安全に行うため、Zod と Hono公式の @hono/zod-validator をインストールします。
npm install zod @hono/zod-validatorStep 3: 設定ファイル(wrangler.jsonc)の編集
プロジェクトルートの wrangler.jsonc を開き、公開環境変数(vars)を追加します。
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "my-hono-api", "main": "src/index.ts", "compatibility_date": "2024-09-01", "compatibility_flags": [ "nodejs_compat" ], // 公開されても良い環境変数を定義 "vars": { "APP_ENV": "development", "APP_NAME": "Cloudflare Hono API" }}Step 4: wrangler types で型定義を自動生成
Wranglerの強力な機能である wrangler types を実行します。
npx wrangler typesこれにより、プロジェクトルートに worker-configuration.d.ts が生成されます。wrangler.jsonc の vars や後述するシークレットが自動的に TypeScript の型として登録されます。
Step 5: Hono APIコードの実装
src/index.ts を開き、以下の完成コードに置き換えます。
import { Hono } from 'hono';import { z } from 'zod';import { zValidator } from '@hono/zod-validator';
// 1. 環境変数の型定義(wrangler types で生成される Env 型を拡張)type Bindings = Env & { API_SECRET_TOKEN: string;};
// メモ(Todo)の型定義type Todo = { id: string; title: string; completed: boolean; createdAt: string;};
// インメモリデータストア(チュートリアル用)const todos: Todo[] = [ { id: '1', title: 'Cloudflare CLIをマスターする', completed: false, createdAt: new Date().toISOString(), },];
// Honoアプリケーションの初期化(型安全なBindingsを注入)const app = new Hono<{ Bindings: Bindings }>();
// 2. ヘルスチェック(認証不要)app.get('/api/health', (c) => { return c.json({ status: 'healthy', app: c.env.APP_NAME, env: c.env.APP_ENV, timestamp: new Date().toISOString(), });});
// 3. 認証ミドルウェア(/api/todos 配下に適用)app.use('/api/todos/*', async (c, next) => { const authHeader = c.req.header('Authorization'); const expectedToken = `Bearer ${c.env.API_SECRET_TOKEN}`;
if (!authHeader || authHeader !== expectedToken) { return c.json( { error: 'Unauthorized: 有効な Bearer トークンを指定してください' }, 401 ); } await next();});
// 4. 一覧取得(GET)app.get('/api/todos', (c) => { return c.json({ count: todos.length, todos: todos, });});
// 5. 作成スキーマ定義(Zod)const createTodoSchema = z.object({ title: z.string().min(1, 'タイトルは必須です').max(100, 'タイトルは100文字以内で指定してください'),});
// 6. 新規作成(POST)app.post('/api/todos', zValidator('json', createTodoSchema), async (c) => { const { title } = c.req.valid('json');
const newTodo: Todo = { id: (todos.length + 1).toString(), title, completed: false, createdAt: new Date().toISOString(), };
todos.push(newTodo); return c.json(newTodo, 201);});
// 7. 削除(DELETE)app.delete('/api/todos/:id', (c) => { const id = c.req.param('id'); const index = todos.findIndex((t) => t.id === id);
if (index === -1) { return c.json({ error: '指定されたTodoが見つかりません' }, 404); }
const [deleted] = todos.splice(index, 1); return c.json({ message: '削除しました', deleted });});
export default app;Step 6: ローカルシークレット(.dev.vars)の作成
コード内で参照している機密情報 API_SECRET_TOKEN をローカル開発時に読み込ませるため、プロジェクト直下に .dev.vars を作成します。
# .dev.vars ファイルを作成echo 'API_SECRET_TOKEN="my-secret-token-12345"' > .dev.vars[!CAUTION] Gitへのコミット禁止
.dev.varsにはパスワードやシークレットが平文で保存されます。C3の初期設定で.gitignoreに含まれていることを必ず確認してください。
Step 7: ローカルサーバー起動と curl 動作検証
ローカル開発サーバーを立ち上げます。
npx wrangler devターミナルに Ready on http://localhost:8787 と表示されたら、別のターミナルを開いて curl でテストします。
1. ヘルスチェック(認証なしで成功)
curl -i http://localhost:8787/api/healthレスポンス:
HTTP/1.1 200 OK{ "status": "healthy", "app": "Cloudflare Hono API", "env": "development", "timestamp": "2026-09-21T00:00:00.000Z"}2. 認証なしでアクセス(401エラーになることを確認)
curl -i http://localhost:8787/api/todosレスポンス:
HTTP/1.1 401 Unauthorized{ "error": "Unauthorized: 有効な Bearer トークンを指定してください"}3. 正しいトークンで一覧取得(200成功)
curl -i http://localhost:8787/api/todos \ -H "Authorization: Bearer my-secret-token-12345"4. 新規Todoの作成(POST)
curl -i -X POST http://localhost:8787/api/todos \ -H "Authorization: Bearer my-secret-token-12345" \ -H "Content-Type: application/json" \ -d '{"title": "HonoとCloudflareの連携完了!"}'レスポンス:
HTTP/1.1 201 Created{ "id": "2", "title": "HonoとCloudflareの連携完了!", "completed": false, "createdAt": "2026-09-21T00:01:00.000Z"}5. バリデーションエラーのテスト(空文字タイトル)
curl -i -X POST http://localhost:8787/api/todos \ -H "Authorization: Bearer my-secret-token-12345" \ -H "Content-Type: application/json" \ -d '{"title": ""}'レスポンス(Zodにより自動で400が返却される):
HTTP/1.1 400 Bad Request{ "success": false, "error": { ... "message": "タイトルは必須です" }}Step 8: 本番シークレット登録と世界へのデプロイ
動作確認ができたら、いよいよ本番環境へデプロイします。
1. 本番用シークレットの登録
本番サーバー上では .dev.vars は使えません。Wrangler CLIを使って暗号化保存します。
npx wrangler secret put API_SECRET_TOKENプロンプトが表示されたら、本番用のランダムなセキュア文字列(例: prod-super-secure-token-98765)を入力してEnterを押します。
2. 本番デプロイの実行
npx wrangler deployデプロイ成功時の出力:
Total Upload: 45.21 KiB / gzip: 11.34 KiBUploaded my-hono-api (1.82 sec)Deployed my-hono-api triggers (0.35 sec) https://my-hono-api.your-subdomain.workers.devCurrent Version ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx3. 本番URLでの最終確認
ターミナルに表示された workers.dev URLに対してリクエストを送信します。
curl https://my-hono-api.your-subdomain.workers.dev/api/health世界330拠点以上のエッジから、わずか数ミリ秒でレスポンスが返ってくることを体感できます!
まとめと次のステップ
このチュートリアルで、以下の基本サイクルを完全に習得できました。
- C3 で雛形生成
wrangler.jsoncとwrangler typesで型安全性の確保.dev.varsでのローカル秘匿情報の扱いwrangler devとcurlによる確実な動作検証wrangler secret putとwrangler deployによるセキュアな本番公開
次章(第5章)では、このメモリ上のデータを永続化するために、エッジデータベース Cloudflare D1(SQLite) を導入してCLIからマイグレーション・クエリを実行する実践に進みます。
💡 用語解説コラム
[!NOTE] V8 Isolate (V8アイソレート)
Cloudflare Workersが採用している実行基盤。Node.jsのようにサーバーごとに重いプロセスやVMを起動するのではなく、数ミリ秒で数千個起動できる軽量サンドボックス環境です。コールドスタート(起動待ち)がほぼゼロ(数ミリ秒以下)なのが特徴です。
[!NOTE] 型安全 (Type Safety)
TypeScript等でプログラム実行前にデータ型の不一致やバグをコンパイラが検知する性質。wrangler typesを使うことで、環境変数やDBカラムの記述ミスを実行前に100%防げます。