0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Hono.js × Cloudflare Workers で始めるエッジ API 開発 — Express 経験者のための入門ガイド

0
Posted at

Hono.js × Cloudflare Workers で始めるエッジ API 開発 — Express 経験者のための入門ガイド【2026年版】

本記事のバージョン情報

  • Hono: v4.x
  • Wrangler: v3.x
  • Node.js: v20 以上推奨

はじめに: 「Express でいいじゃん」と思っていた頃の話

正直に言いましょう。

最初に Hono.js を見たとき、「また新しいフレームワーク...」と思いました。

Express で十分じゃないか、と。ルーティング書いて、ミドルウェア積んで、app.listen(3000) して終わり。その流れは慣れていたし、特に不満もなかった。

ただ、ある日 Cloudflare Workers にデプロイしようとしたとき、ちょっと詰まったんです。

Node.js の http モジュールが使えない。fs も一部使えない。Express がそもそも動かない環境だと気づいた。

そこで出会ったのが Hono.js でした。

「Web 標準 API に準拠している」というキャッチフレーズ、最初はピンとこなかったけれど、実際に書いてみると、なんかスッキリしてるんです。Request と Response がブラウザの fetch と同じ概念で動く。Cloudflare Workers でも、Deno でも、Bun でも、Node.js でも、同じコードが動く。

それって地味なようで、かなり大きな話だと思うんです。


Hono.js とは何か — Express との比較で理解する

Hono(ホノ)は、日本人エンジニアの yusukebe さんが作ったWebフレームワークです。2022年頃から注目を集め、今では GitHub スターも 2 万を超えています。

一言で言うと、**「Web 標準ベースの、軽量で高速な Express ライクなフレームワーク」**です。

Express との主な違い

項目 Express Hono
ランタイム Node.js のみ Cloudflare Workers, Deno, Bun, Node.js 等
ベース Node.js の http モジュール Web 標準 API (Request/Response)
TypeScript 後付け (@types) ファーストクラスサポート
バンドルサイズ 200KB+ ~15KB
型安全ルーティング なし RPC モードで実現

ポイントは「Web 標準 API ベース」という設計思想です。

ブラウザの fetch() が返す Response オブジェクト、同じものがサーバー側でも使われています。Node.js が独自実装してきた部分を Web 標準に揃えることで、どのランタイムでも同じように動くようになっているわけです。

Express を知っていれば、Hono の書き方はすぐ馴染みます。

// Express
import express from 'express';
const app = express();
app.get('/', (req, res) => {
  res.json({ message: 'Hello' });
});

// Hono
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => {
  return c.json({ message: 'Hello' });
});

req, resc(Context オブジェクト)にまとまっている。それだけの違いです。慣れれば逆にこちらの方が整理されていて書きやすいと感じるかもしれないです。


環境構築と最初の一歩

まず Cloudflare のアカウントが必要です。無料プランで十分で、Workers は 1 日 10 万リクエストまで無料枠で使えます。

Step 1: wrangler のインストール

npm install -g wrangler
wrangler login

wrangler login でブラウザが開き、Cloudflare アカウントで認証します。これだけでローカルからデプロイできる環境が整います。

Step 2: Hono プロジェクトの作成

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   ← Cloudflare Workers の設定
  ├── tsconfig.json
  └── package.json

src/index.ts を開くと、最小限の Hono アプリが書かれています。

import { Hono } from 'hono';

const app = new Hono();

app.get('/', (c) => {
  return c.text('Hello Hono!');
});

export default app;

Step 3: ローカル開発サーバーの起動

npm run dev

http://localhost:8787 でアクセスできます。ファイルを変更すると自動で再読み込みされます。


ルーティング・レスポンス・ミドルウェアの基本

ルーティング

Express とほぼ同じ感覚で書けます。

import { Hono } from 'hono';

const app = new Hono();

// GET
app.get('/users', (c) => {
  return c.json({ users: [] });
});

// POST
app.post('/users', async (c) => {
  const body = await c.req.json();
  return c.json({ created: body }, 201);
});

// パスパラメータ
app.get('/users/:id', (c) => {
  const id = c.req.param('id');
  return c.json({ id });
});

// クエリパラメータ
app.get('/search', (c) => {
  const q = c.req.query('q');
  return c.json({ query: q });
});

export default app;

Context オブジェクト (c) に全部集約されているのが Hono の特徴です。c.req でリクエスト情報を取得し、c.json(), c.text(), c.html() でレスポンスを返します。

ミドルウェア

組み込みミドルウェアが充実しています。

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { prettyJSON } from 'hono/pretty-json';

const app = new Hono();

// CORS の設定
app.use('/*', cors({
  origin: 'https://example.com',
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
}));

// リクエストロガー
app.use('/*', logger());

// 開発時の見やすい JSON 出力
app.use('/*', prettyJSON());

app.get('/', (c) => c.json({ status: 'ok' }));

export default app;

use() でグローバルミドルウェアを適用します。パスパターンで適用範囲を絞ることもできます。

バリデーション

@hono/zod-validator を使うと、Zod で入力バリデーションができます。

npm install zod @hono/zod-validator
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

const app = new Hono();

const createUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

app.post(
  '/users',
  zValidator('json', createUserSchema),
  (c) => {
    const { name, email } = c.req.valid('json');
    // バリデーション通過後のデータは型が確定している
    return c.json({ name, email }, 201);
  }
);

export default app;

c.req.valid('json') でバリデーション済みのデータを取得できます。この時点で TypeScript の型が完全に推論されています。バリデーションと型安全が同時に手に入る、これはかなり便利です。

環境変数(Bindings)

Cloudflare Workers では環境変数を Bindings として扱います。

// wrangler.toml
// [vars]
// API_KEY = "your-secret"

type Bindings = {
  API_KEY: string;
};

const app = new Hono<{ Bindings: Bindings }>();

app.get('/secret', (c) => {
  const apiKey = c.env.API_KEY;
  return c.json({ key: apiKey });
});

export default app;

Hono<{ Bindings: Bindings }> と型パラメータを指定することで、c.env に型補完が効くようになります。このあたりの TypeScript との統合感は、Express にはなかった感覚です。


型安全 API の体験 — Hono RPC モード入門

Hono の面白い機能のひとつが RPC モードです。

通常、フロントエンドから API を呼ぶとき、エンドポイントの URL と型を手で管理しますよね。/api/usersUser[] を返す、みたいな暗黙知。それが壊れたとき、実行時に気づく。

Hono の RPC モードを使うと、サーバーで定義した型をクライアント側でそのまま使えるようになります。

サーバー側

import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

const app = new Hono();

const routes = app
  .get('/api/users', (c) => {
    return c.json([
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' },
    ]);
  })
  .post(
    '/api/users',
    zValidator('json', z.object({ name: z.string() })),
    (c) => {
      const { name } = c.req.valid('json');
      return c.json({ id: 3, name }, 201);
    }
  );

export type AppType = typeof routes;
export default app;

typeof routes でルートの型情報を取り出しています。これをクライアント側に共有します。

クライアント側(同じリポジトリの場合)

import { hc } from 'hono/client';
import type { AppType } from './server';

const client = hc<AppType>('http://localhost:8787');

// GET /api/users — レスポンスの型が自動で推論される
const res = await client.api.users.$get();
const users = await res.json();
// users は { id: number; name: string }[] と推論される

// POST /api/users — リクエストボディも型チェックされる
const createRes = await client.api.users.$post({
  json: { name: 'Charlie' },
  // json: { age: 25 } — これは型エラーになる
});

client.api.users.$get() と書くだけで、型補完が効いてレスポンスの型も分かる。$post() ではリクエストボディの型チェックもしてくれます。

正直、最初にこれを動かしたとき「これはすごい...」と思いました。

tRPC と似た体験を、より薄いレイヤーで実現している感じです。フロントエンドとバックエンドを同じリポジトリで管理する monorepo 構成だと、特に効果が大きいです。


Cloudflare Workers へのデプロイ(wrangler deploy 一発)

ローカルで動いたら、デプロイは本当にシンプルです。

wrangler deploy

これだけです。

成功すると、

Published my-api (1.23 sec)
  https://my-api.your-name.workers.dev

のような URL が表示されます。即座に本番環境で動きます。CDN の前に置く設定とか、サーバーを立ち上げる作業とか、そういった手順が一切ない。これが Cloudflare Workers の体験的な良さだと思います。

本番用の環境変数の設定

wrangler secret put API_KEY

コマンドを実行するとパスワード入力のようなプロンプトが出て、秘密情報を安全に設定できます。コードに書かなくていい。

カスタムドメインの設定

wrangler.toml に以下を追記することで、独自ドメインで公開できます。

[env.production]
routes = [
  { pattern = "api.example.com/*", zone_name = "example.com" }
]

知っておきたい注意点・制限事項

Cloudflare Workers は強力ですが、いくつか制限があります。入門の段階で知っておくと、後で「なぜ動かないんだろう...」と詰まるのを防げます。

Node.js 標準モジュールの制限

  • fs(ファイルシステム)は使えない
  • crypto は一部 Web 標準の crypto が使えるが、Node.js の crypto モジュールとは異なる
  • child_process は使えない

対策: wrangler.tomlcompatibility_flags = ["nodejs_compat"] を追加することで、Node.js の一部モジュールが使えるようになります。

compatibility_flags = ["nodejs_compat"]

実行時間の制限

無料プランでは CPU 時間が 10ms 以内という制限があります。重い処理には向いていないです。有料プランでは 30 秒まで延長できます。

ステートレスな実行

各リクエストはステートレスです。インメモリでの状態管理はリクエストをまたいで持続しません。永続化が必要なら Cloudflare D1(SQLite)、KV、R2(オブジェクトストレージ)といったサービスと組み合わせます。

WebSocket

WebSocket は upgrade でのハンドシェイクに対応していますが、長時間接続は Durable Objects が必要になります。


まとめ: Hono が変えるバックエンド開発の感覚

Hono.js を使い始めて感じたのは、「フレームワークがランタイムに縛られなくなった」という感覚です。

Express はすごいフレームワークだと思うし、今でも使われ続けると思います。ただ、Cloudflare Workers のようなエッジランタイムが普及してくると、Node.js 専用の設計では対応できない場面が増えてきます。

Hono は Web 標準に乗ることで、その問題をエレガントに解決しています。Express のように書けて、TypeScript の型補完が効いて、どのランタイムでも動く。これは地味に大きな進化だと思うんです。

今日試してみるなら

npm create hono@latest my-first-api
cd my-first-api
npm install
npm run dev

これだけで動き始めます。デプロイも wrangler deploy 一発。ぜひ体験してみてください。

RPC モードを使った型安全 API の感触、一度味わうと戻れなくなるかもしれないです。


参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?