コンテンツにスキップ

第4章: Hono × Workers で作る爆速型安全API(実践チュートリアル)

本章では、軽量・Web標準準拠のフレームワーク HonoCloudflare Workers を組み合わせ、認証付き・型安全なREST APIをゼロから構築して世界へデプロイするハンズオンを実施します。


本チュートリアルで作成するもの

  • API機能:
    • GET /api/health(ヘルスチェック)
    • GET /api/todos(一覧取得)
    • POST /api/todos(Zodによるスキーマ検証付き作成)
    • DELETE /api/todos/:id(削除)
  • セキュリティ:
    • APIシークレットキーによるBearerトークン認証ミドルウェア
  • DX(開発者体験):
    • wrangler types による環境変数の完全型補完
    • .dev.varswrangler 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)でプロジェクト作成

ターミナルを開き、以下のコマンドを実行します。

Terminal window
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 (後ほど設定・テストしてからデプロイします)

作成されたディレクトリに移動します。

Terminal window
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 をインストールします。

Terminal window
npm install zod @hono/zod-validator

Step 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 を実行します。

Terminal window
npx wrangler types

これにより、プロジェクトルートに worker-configuration.d.ts が生成されます。wrangler.jsoncvars や後述するシークレットが自動的に 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 を作成します。

Terminal window
# .dev.vars ファイルを作成
echo 'API_SECRET_TOKEN="my-secret-token-12345"' > .dev.vars

[!CAUTION] Gitへのコミット禁止
.dev.vars にはパスワードやシークレットが平文で保存されます。C3の初期設定で .gitignore に含まれていることを必ず確認してください。


Step 7: ローカルサーバー起動と curl 動作検証

ローカル開発サーバーを立ち上げます。

Terminal window
npx wrangler dev

ターミナルに Ready on http://localhost:8787 と表示されたら、別のターミナルを開いて curl でテストします。

1. ヘルスチェック(認証なしで成功)

Terminal window
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エラーになることを確認)

Terminal window
curl -i http://localhost:8787/api/todos

レスポンス:

HTTP/1.1 401 Unauthorized
{
"error": "Unauthorized: 有効な Bearer トークンを指定してください"
}

3. 正しいトークンで一覧取得(200成功)

Terminal window
curl -i http://localhost:8787/api/todos \
-H "Authorization: Bearer my-secret-token-12345"

4. 新規Todoの作成(POST)

Terminal window
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. バリデーションエラーのテスト(空文字タイトル)

Terminal window
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を使って暗号化保存します。

Terminal window
npx wrangler secret put API_SECRET_TOKEN

プロンプトが表示されたら、本番用のランダムなセキュア文字列(例: prod-super-secure-token-98765)を入力してEnterを押します。

2. 本番デプロイの実行

Terminal window
npx wrangler deploy

デプロイ成功時の出力:

Total Upload: 45.21 KiB / gzip: 11.34 KiB
Uploaded my-hono-api (1.82 sec)
Deployed my-hono-api triggers (0.35 sec)
https://my-hono-api.your-subdomain.workers.dev
Current Version ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

3. 本番URLでの最終確認

ターミナルに表示された workers.dev URLに対してリクエストを送信します。

Terminal window
curl https://my-hono-api.your-subdomain.workers.dev/api/health

世界330拠点以上のエッジから、わずか数ミリ秒でレスポンスが返ってくることを体感できます!


まとめと次のステップ

このチュートリアルで、以下の基本サイクルを完全に習得できました。

  1. C3 で雛形生成
  2. wrangler.jsoncwrangler types で型安全性の確保
  3. .dev.vars でのローカル秘匿情報の扱い
  4. wrangler devcurl による確実な動作検証
  5. wrangler secret putwrangler deploy によるセキュアな本番公開

次章(第5章)では、このメモリ上のデータを永続化するために、エッジデータベース Cloudflare D1(SQLite) を導入してCLIからマイグレーション・クエリを実行する実践に進みます。


💡 用語解説コラム

[!NOTE] V8 Isolate (V8アイソレート)
Cloudflare Workersが採用している実行基盤。Node.jsのようにサーバーごとに重いプロセスやVMを起動するのではなく、数ミリ秒で数千個起動できる軽量サンドボックス環境です。コールドスタート(起動待ち)がほぼゼロ(数ミリ秒以下)なのが特徴です。

[!NOTE] 型安全 (Type Safety)
TypeScript等でプログラム実行前にデータ型の不一致やバグをコンパイラが検知する性質。wrangler typesを使うことで、環境変数やDBカラムの記述ミスを実行前に100%防げます。