h3 の使い方

Minimal H(TTP) framework built for high performance and portability.

v2.0.1-rc.20/週MITWeb API
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

h3 の使い方 — 高性能・ポータブルなHTTPフレームワーク

一言でいうと

h3 は、UnJS エコシステムが提供する軽量・高性能な HTTP フレームワークです。Node.js だけでなく、Cloudflare Workers・Deno・Bun・Vercel Edge Functions など、あらゆるランタイムで動作するポータブルな設計が最大の特徴です。

どんな時に使う?

  • Nitro / Nuxt のカスタムサーバーAPI を書くとき — Nuxt 3 の server/api/ ディレクトリの裏側で動いているのが h3 です。仕組みを理解しておくとデバッグや拡張が格段に楽になります。
  • エッジランタイム対応の軽量 API サーバーを構築したいとき — Express のような Node.js 固有の API に依存せず、Web 標準(Request / Response)ベースで動作するサーバーが必要な場面に最適です。
  • マイクロサービスや BFF(Backend for Frontend)を最小構成で立てたいとき — 依存が極めて少なく、起動が高速なため、コンテナやサーバーレス環境との相性が抜群です。

インストール

# npm
npm install h3

# yarn
yarn add h3

# pnpm
pnpm add h3

注意: この記事は h3 v2(2.0.1-rc.20)を基に執筆しています。v1 系とは API が大きく異なる部分があります。v1 からの移行時は公式マイグレーションガイドを必ず確認してください。

基本的な使い方

最もシンプルな HTTP サーバーの例です。

import { createApp, createRouter, defineEventHandler } from "h3";

const app = createApp();
const router = createRouter();

router.get(
  "/",
  defineEventHandler(() => {
    return { message: "Hello, h3!" };
  })
);

router.get(
  "/users/:id",
  defineEventHandler((event) => {
    const id = getRouterParam(event, "id");
    return { userId: id };
  })
);

app.use(router);

export default app;

Node.js で起動する場合

import { createApp, createRouter, defineEventHandler, toNodeHandler } from "h3";
import { createServer } from "node:http";

const app = createApp();
const router = createRouter();

router.get(
  "/",
  defineEventHandler(() => {
    return { message: "Hello, h3!" };
  })
);

app.use(router);

const server = createServer(toNodeHandler(app));
server.listen(3000, () => {
  console.log("Server running at http://localhost:3000");
});

Web 標準(Fetch API)で起動する場合(Bun / Deno / Cloudflare Workers)

import { createApp, createRouter, defineEventHandler, toWebHandler } from "h3";

const app = createApp();
const router = createRouter();

router.get(
  "/",
  defineEventHandler(() => {
    return { message: "Hello from the edge!" };
  })
);

app.use(router);

const handler = toWebHandler(app);

// Bun の場合
export default { port: 3000, fetch: handler };

// Deno の場合
// Deno.serve({ port: 3000 }, handler);

よく使う API

1. readBody — リクエストボディの取得

import { defineEventHandler, readBody } from "h3";

router.post(
  "/users",
  defineEventHandler(async (event) => {
    const body = await readBody<{ name: string; email: string }>(event);
    return { created: true, user: body };
  })
);

2. getQuery — クエリパラメータの取得

import { defineEventHandler, getQuery } from "h3";

router.get(
  "/search",
  defineEventHandler((event) => {
    const query = getQuery<{ q: string; page?: string }>(event);
    return { keyword: query.q, page: Number(query.page) || 1 };
  })
);

3. getRouterParam / getRouterParams — パスパラメータの取得

import { defineEventHandler, getRouterParam, getRouterParams } from "h3";

router.get(
  "/users/:userId/posts/:postId",
  defineEventHandler((event) => {
    // 個別に取得
    const userId = getRouterParam(event, "userId");

    // まとめて取得
    const params = getRouterParams(event);
    // => { userId: "123", postId: "456" }

    return { userId, postId: params.postId };
  })
);

4. setResponseHeader / setResponseStatus — レスポンスの制御

import {
  defineEventHandler,
  setResponseHeader,
  setResponseStatus,
} from "h3";

router.post(
  "/items",
  defineEventHandler(async (event) => {
    const body = await readBody(event);

    setResponseStatus(event, 201);
    setResponseHeader(event, "X-Custom-Header", "my-value");

    return { created: true, item: body };
  })
);

5. createError — エラーハンドリング

import { createError, defineEventHandler, getRouterParam } from "h3";

router.get(
  "/users/:id",
  defineEventHandler((event) => {
    const id = getRouterParam(event, "id");

    if (!id || isNaN(Number(id))) {
      throw createError({
        statusCode: 400,
        statusMessage: "Bad Request",
        message: "Invalid user ID",
      });
    }

    // ユーザーが見つからない場合
    const user = findUserById(Number(id));
    if (!user) {
      throw createError({
        statusCode: 404,
        statusMessage: "Not Found",
        message: `User ${id} not found`,
      });
    }

    return user;
  })
);

補足: ミドルウェアの定義

import { defineEventHandler, getRequestHeader } from "h3";

// ミドルウェアとして登録(パスなしで app.use に渡す)
app.use(
  defineEventHandler((event) => {
    const auth = getRequestHeader(event, "authorization");
    if (!auth) {
      throw createError({ statusCode: 401, message: "Unauthorized" });
    }
    // 何も返さなければ次のハンドラに処理が渡る
  })
);

類似パッケージとの比較

特徴h3ExpressHonoFastify
ランタイムNode / Bun / Deno / EdgeNode 中心Node / Bun / Deno / EdgeNode 中心
Web 標準準拠✅(v2 で強化)
TypeScript サポート✅ ネイティブ△(@types 必要)✅ ネイティブ✅ ネイティブ
バンドルサイズ極小極小
エコシステムUnJS / Nuxt / Nitro最大規模急成長中プラグイン豊富
ミドルウェア互換Node.js ミドルウェアをアダプタ経由で利用可Express ミドルウェア独自Fastify プラグイン
主な用途Nuxt サーバー / エッジ API汎用 Web サーバーエッジ API / フルスタック高性能 REST API

選定の目安:

  • Nuxt / Nitro を使うなら → h3(必然的に使うことになる)
  • エッジファーストで Hono と迷うなら → API スタイルの好みで選んで OK。h3 は UnJS エコシステムとの統合が強み
  • 既存の Express 資産が多いなら → Express のままか Fastify への移行を検討

注意点・Tips

v1 → v2 の破壊的変更に注意

h3 v2 では多くの API がリネーム・再設計されています。例えば:

  • useBody()readBody()
  • useQuery()getQuery()
  • sendError()throw createError() に統一

v2 はまだ RC(リリース候補)段階です(2.0.1-rc.20 時点)。プロダクション導入時はバージョンを固定し、CHANGELOG を追跡してください。

ハンドラの戻り値がそのままレスポンスになる

h3 では defineEventHandler の戻り値が自動的にレスポンスボディになります。オブジェクトを返せば application/json として、文字列を返せば text/plain としてシリアライズされます。明示的に res.json() を呼ぶ必要はありません。

// JSON レスポンス(自動)
defineEventHandler(() => ({ ok: true }));

// テキストレスポンス(自動)
defineEventHandler(() => "Hello!");

// null を返すと 204 No Content
defineEventHandler(() => null);

event オブジェクトを常に引き回す

Express の req / res と異なり、h3 では統一された event オブジェクトを各ユーティリティ関数に渡す設計です。これにより、ランタイムに依存しない抽象化が実現されています。

// ✅ Good: ユーティリティ関数に event を渡す
const body = await readBody(event);
const query = getQuery(event);

// ❌ Bad: Node.js 固有の API に直接アクセスしない
// event.node.req は Node.js 環境でのみ動作する

パフォーマンス Tips

  • ルーターは createRouter() で作成し、app.use(router) で登録するのが推奨パターンです。内部で radix tree ベースのルーティング(radix3)が使われており、ルート数が増えても高速にマッチングされます。
  • 静的レスポンスはハンドラ外でキャッシュし、ハンドラ内ではオブジェクト生成を最小限にすると、GC 負荷を抑えられます。

まとめ

h3 は「どこでも動く HTTP サーバー」を最小限のコードで実現するフレームワークです。Nuxt 3 / Nitro の基盤として実戦投入されており、信頼性は十分に検証されています。v2 で Web 標準への準拠がさらに強化され、エッジコンピューティング時代の HTTP フレームワークとして有力な選択肢です。Express に慣れたエンジニアでも、event ベースの設計に慣れれば移行はスムーズでしょう。