Context と Request/Response

ハンドラに渡される cContext)が Hono の操作の中心。 リクエストの読み取り、レスポンスの構築、ミドルウェア間の値共有、環境変数アクセスをここで行う。

Context の中身

プロパティ役割
c.reqリクエスト(Hono の HonoRequest ラッパ)
c.resレスポンス
c.env環境変数(Cloudflare Bindings 等)
c.executionCtx実行コンテキスト(Cloudflare の waitUntil 等)
c.eventイベント情報(環境による)
c.varmiddleware 間の値共有
c.set(k, v) / c.get(k)middleware 間で値の受け渡し
c.text/json/html/body/redirectレスポンスヘルパー
c.status(n) / c.header(k, v)レスポンス調整

Request の読み取り(c.req

パス・メソッド・URL

c.req.path           // /users/123
c.req.method         // "GET"
c.req.url            // フル URL
c.req.routePath      // "/users/:id"
c.req.matchedRoutes  // マッチしたルート情報

パラメータ・クエリ

c.req.param("id")          // パスパラメータ
c.req.param()              // 全パラメータ object
c.req.query("q")           // 単一クエリ
c.req.queries("tag")       // 複数クエリ(配列)
c.req.query()              // 全クエリ object

ヘッダー

c.req.header("user-agent")     // 単一
c.req.header()                  // 全ヘッダー object(小文字キー)

// Web 標準の Headers が欲しい時
c.req.raw.headers

ボディの読み取り

// JSON
const data = await c.req.json<{ name: string }>()

// テキスト
const text = await c.req.text()

// FormData
const form = await c.req.formData()
const file = form.get("file") as File | null

// parseBody(URLエンコード or multipart 自動判定)
const body = await c.req.parseBody()
// body.field, body.file 等

// 生 ArrayBuffer
const buf = await c.req.arrayBuffer()

// Blob
const blob = await c.req.blob()

Cookie

import { getCookie, setCookie, deleteCookie } from "hono/cookie"

const sid = getCookie(c, "session_id")
setCookie(c, "session_id", "abc123", {
  httpOnly: true,
  secure: true,
  sameSite: "Lax",
  maxAge: 3600,
  path: "/",
})
deleteCookie(c, "session_id")

低レベル: 生 Request

const raw: Request = c.req.raw
// fetch の Request そのもの

Response の構築

ヘルパー

return c.text("Hello", 200)
return c.json({ ok: true }, 201)
return c.html("<h1>Hi</h1>")
return c.redirect("/login", 302)
return c.notFound()
return c.body(null, 204)         // No Content

ヘッダーの追加

c.header("X-Custom", "value")
c.header("Cache-Control", "max-age=60")
return c.json({ ok: true })

// または直接渡す
return c.json({ ok: true }, 200, {
  "X-Custom": "value",
  "Cache-Control": "max-age=60",
})

低レベル: Response 直接

return new Response("Raw", { status: 200, headers: { "Content-Type": "text/plain" } })

// または c.newResponse
return c.newResponse("Raw", 200, { "Content-Type": "text/plain" })

環境変数(c.env

Cloudflare Workers のBindings(KV, Durable Objects, R2, D1, Secrets)はここから。

type Bindings = {
  DB: D1Database
  KV: KVNamespace
  AI: Ai
  SECRET_KEY: string
}

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

app.get("/", async (c) => {
  const result = await c.env.DB.prepare("SELECT 1").first()
  const cached = await c.env.KV.get("key")
  return c.json({ result, cached })
})

Node.js / Bun では process.env ベースで自分で型を作る。

Variables(middleware 間の値共有)

ある middleware で計算した値を、後続のハンドラで使う。request-scoped

type Variables = {
  user: { id: string, name: string }
  requestId: string
}

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

app.use(async (c, next) => {
  c.set("requestId", crypto.randomUUID())
  await next()
})

app.use("/api/*", async (c, next) => {
  const token = c.req.header("authorization")
  if (!token) return c.text("Unauthorized", 401)
  const user = await verifyToken(token)
  c.set("user", user)
  await next()
})

app.get("/api/me", (c) => {
  const user = c.get("user")           // 型推論される
  const id = c.var.requestId           // c.var でも OK
  return c.json({ user, id })
})

executionCtx と waitUntil

Cloudflare Workers では「レスポンスを返した後でも実行を続ける」ことが executionCtx.waitUntil でできる。 解析・ロギング・キャッシュ更新の定石。

app.get("/api/data", (c) => {
  c.executionCtx.waitUntil(
    logToAnalytics({ path: c.req.path, ts: Date.now() })
  )
  return c.json({ data: ... })
})

型を全体で共有

Bindings / Variables をモジュール全体で使うため、型を1か所に集めてアプリ全体に伝播させる。

app.ts
export type AppEnv = {
  Bindings: { DB: D1Database }
  Variables: { user?: User }
}

export const app = new Hono<AppEnv>()
routes/users.ts
import { Hono } from "hono"
import type { AppEnv } from "../app"

const users = new Hono<AppEnv>()
users.get("/", (c) => {
  // c.env.DB が型付きで使える
})
export default users

req.valid(バリデータ連携)

@hono/zod-validator 等を通すと、検証済みの値が c.req.valid("json") 等で取れる。 詳細は バリデーション

標準 fetch との互換

Hono のハンドラの引数は Context だが、内部で扱っているのは Web 標準の Request/Response。 どこでも fetch の世界観で書ける。

トリビア

c.req は HonoRequest クラス。便利メソッドが乗っている。
素の Request が欲しい時は c.req.raw