Tasuke Hubのロゴ

ITを中心に困っている人を助けるメディア

分かりやすく解決策を提供することで、あなたの困ったをサポート。 全ての人々がスムーズに生活できる世界を目指します。

Honoで始める高速Webアプリ開発入門!TypeScriptフレームワークの特徴と実装例

記事のサムネイル

Honoとは?軽量高速なWebフレームワークの特徴

Hono(ホノ)は日本語で「炎🔥」を意味する、超軽量で高速なTypeScript/JavaScriptのWebフレームワークです。Web標準APIに基づいて構築されており、さまざまなJavaScriptランタイム環境で動作する汎用性が特徴です。2025年現在、最新バージョンは4.7系となり、多くの開発者から支持を集めています。

Honoの主な特徴を見ていきましょう:

  • 超高速なルーティング: RegExpRouterを採用し、線形ループを使わない高速な処理を実現
  • 超軽量: 最小構成(hono/tiny)では12KB未満というサイズ
  • マルチランタイム対応: Cloudflare Workers、Fastly Compute、Deno、Bun、Vercel、AWS Lambda、Node.jsなど多様な環境に対応
  • 機能が豊富: 標準で多数のミドルウェアやヘルパーを内蔵
  • 優れた開発体験: クリーンなAPI設計と一流のTypeScriptサポート

他のフレームワークと比較すると、Express.jsが成熟した歴史を持つ一方で、Honoは最新のWeb標準に基づいた設計思想と軽量さが魅力となっています。特に、Cloudflare Workersのようなエッジコンピューティング環境での使用に最適化されている点が大きな特徴です。

// Honoの基本的な使い方の例
import { Hono } from 'hono'

const app = new Hono()

// ルートへのGETリクエストを処理
app.get('/', (c) => c.text('Hello Hono!'))

// JSONデータを返すAPI
app.get('/api/user', (c) => {
  return c.json({
    id: 1,
    name: 'Taro',
    email: '[email protected]'
  })
})

export default app

このシンプルな例からもわかるように、Honoはミニマルな記述でAPIエンドポイントを定義できます。TypeScriptとの相性も良く、型安全なアプリケーション開発が可能です。

次のセクションでは、実際にHonoを使ったAPI開発の基本的な実装例を紹介します。

Hono入門!シンプルな実装例で始めるAPI開発

Honoを使った開発を始めるには、まずプロジェクトの初期設定が必要です。ここでは、Node.jsを使った基本的なセットアップ手順を紹介します。

インストールと初期設定

# 新しいプロジェクトディレクトリを作成
mkdir hono-api-example
cd hono-api-example

# package.jsonの初期化
npm init -y

# Honoとその依存関係をインストール
npm install hono

# 開発用にTypeScript関連パッケージをインストール
npm install --save-dev typescript ts-node @types/node

基本的なAPIの作成

では、実際に簡単なRESTful APIを作ってみましょう。以下は、ユーザー情報を管理するAPIの例です。

// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'

// アプリケーションのインスタンスを作成
const app = new Hono()

// ロガーミドルウェアを適用
app.use('*', logger())

// インメモリデータベースの代わりに配列を使用
const users = [
  { id: 1, name: '山田太郎', email: '[email protected]' },
  { id: 2, name: '佐藤花子', email: '[email protected]' }
]

// 全ユーザー取得API
app.get('/api/users', (c) => {
  return c.json(users)
})

// IDによるユーザー取得API
app.get('/api/users/:id', (c) => {
  const id = parseInt(c.req.param('id'))
  const user = users.find(u => u.id === id)
  
  if (!user) {
    return c.json({ message: 'ユーザーが見つかりません' }, 404)
  }
  
  return c.json(user)
})

// 新規ユーザー作成API
app.post('/api/users', async (c) => {
  const body = await c.req.json()
  
  // バリデーションチェック
  if (!body.name || !body.email) {
    return c.json({ message: '名前とメールアドレスは必須です' }, 400)
  }
  
  const newUser = {
    id: users.length + 1,
    name: body.name,
    email: body.email
  }
  
  users.push(newUser)
  return c.json(newUser, 201)
})

// サーバー起動(Node.js環境の場合)
import { serve } from '@hono/node-server'
serve(app, (info) => {
  console.log(`Server is running on http://localhost:${info.port}`)
})

型安全なリクエスト処理

Honoは優れたTypeScriptサポートを持ち、型安全なAPIを簡単に開発できます。下記は、Zodを使用した型バリデーションの例です。

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

const app = new Hono()

// ユーザースキーマの定義
const userSchema = z.object({
  name: z.string().min(1, { message: '名前は必須です' }),
  email: z.string().email({ message: '有効なメールアドレスを入力してください' }),
  age: z.number().int().positive().optional()
})

// 型の抽出
type User = z.infer<typeof userSchema>

// バリデーション付きのユーザー作成エンドポイント
app.post('/api/users', zValidator('json', userSchema), async (c) => {
  // バリデーション済みのデータを取得
  const userData = c.req.valid('json')
  
  // データベース処理などの実装...
  
  return c.json({ 
    message: 'ユーザーが作成されました', 
    user: userData 
  }, 201)
})

このように、Honoでは少ないコード量で型安全なAPIを実装できます。次のセクションでは、Honoのミドルウェアについて詳しく解説します。

ミドルウェアを活用したHonoアプリケーション開発

Honoの強力な機能の一つがミドルウェアシステムです。ミドルウェアを使用することで、リクエストとレスポンスの処理をカスタマイズし、再利用可能なコンポーネントを作成できます。

ミドルウェアの基本概念

Honoにおけるミドルウェアは、リクエストを処理するハンドラの前後に実行される関数です。これは「玉ねぎ構造」と呼ばれ、リクエストが内側のハンドラに到達する前と、レスポンスが外側に戻る際に処理を挟むことができます。

import { Hono } from 'hono'

const app = new Hono()

// シンプルなミドルウェアの例
app.use('*', async (c, next) => {
  console.log('リクエスト開始:', c.req.url)
  
  // リクエスト処理時間を計測
  const startTime = Date.now()
  
  // 次のミドルウェアまたはハンドラを実行
  await next()
  
  // レスポンスにレスポンスタイムヘッダーを追加
  const endTime = Date.now()
  c.header('X-Response-Time', `${endTime - startTime}ms`)
  
  console.log('リクエスト完了:', c.req.url)
})

app.get('/', (c) => c.text('Hello World!'))

export default app

組み込みミドルウェア

Honoには多くの組み込みミドルウェアが用意されており、一般的なWebアプリケーション機能を簡単に実装できます。

import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
import { basicAuth } from 'hono/basic-auth'
import { compress } from 'hono/compress'

const app = new Hono()

// リクエストロギング
app.use('*', logger())

// CORS設定
app.use('*', cors({
  origin: ['https://example.com', 'https://api.example.com'],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization'],
  exposeHeaders: ['X-Total-Count'],
  maxAge: 86400
}))

// 圧縮ミドルウェア(レスポンスを圧縮して転送量を削減)
app.use('*', compress())

// 管理者向けエンドポイントに基本認証を適用
app.use('/admin/*', basicAuth({
  username: 'admin',
  password: process.env.ADMIN_PASSWORD || 'secret'
}))

// 管理者ダッシュボード
app.get('/admin/dashboard', (c) => {
  return c.text('管理者ダッシュボードへようこそ!')
})

// 一般公開API
app.get('/api/public', (c) => {
  return c.json({ message: '誰でもアクセスできるAPI' })
})

export default app

カスタムミドルウェアの作成

特定のニーズに合わせて独自のミドルウェアを作成することも簡単です。以下は、アクセストークンを検証するJWTミドルウェアの例です。

import { Hono } from 'hono'
import { jwt } from 'hono/jwt'

const app = new Hono()

// JWT認証ミドルウェア
const verifyAuth = jwt({
  secret: process.env.JWT_SECRET || 'your-secret-key'
})

// 認証不要のパブリックルート
app.get('/public', (c) => {
  return c.text('パブリックコンテンツ')
})

// 保護されたルートグループ
app.use('/api/protected/*', verifyAuth)

app.get('/api/protected/profile', (c) => {
  // JWT検証が成功するとペイロードがコンテキストに追加される
  const payload = c.get('jwtPayload')
  return c.json({
    message: '認証済みユーザー',
    userId: payload.sub
  })
})

// JWT認証エラーハンドラ
app.onError((err, c) => {
  if (err.message.includes('JWT')) {
    return c.json({ error: '認証に失敗しました' }, 401)
  }
  
  console.error('エラー:', err)
  return c.json({ error: 'サーバーエラー' }, 500)
})

export default app

ミドルウェアのスコープと実行順序

ミドルウェアは特定のパスパターンやHTTPメソッドに限定して適用することができます。また、実行順序は登録された順番に従います。

import { Hono } from 'hono'

const app = new Hono()

// グローバルミドルウェア(すべてのルートに適用)
app.use('*', async (c, next) => {
  console.log('グローバルミドルウェア実行')
  await next()
})

// 特定のパスパターンに対するミドルウェア
app.use('/api/*', async (c, next) => {
  console.log('APIミドルウェア実行')
  await next()
})

// 特定のエンドポイントに対するミドルウェア
app.use('/api/users', async (c, next) => {
  console.log('ユーザーAPIミドルウェア実行')
  await next()
})

app.get('/api/users', (c) => {
  // 上記のミドルウェアがすべて実行された後にこのハンドラが呼ばれる
  return c.text('ユーザー一覧')
})

export default app

このように、Honoのミドルウェアシステムは柔軟で強力でありながら、シンプルに記述できることが特徴です。各ミドルウェアは特定の機能に集中し、それらを組み合わせることで複雑なアプリケーションロジックを構築できます。

マルチランタイム対応!さまざまな環境で動作するHonoの実力

Honoの最大の特徴の一つが、様々なJavaScriptランタイム環境で同じコードを実行できる「マルチランタイム対応」です。これにより、一度書いたコードを異なる環境で再利用できるため、開発効率が大幅に向上します。

対応ランタイム環境

Honoは以下のような多様なランタイム環境で動作します:

  • Cloudflare Workers - エッジでの高速な実行が可能
  • Fastly Compute - 低レイテンシーのエッジコンピューティング
  • Deno - セキュリティ重視のモダンなJavaScriptランタイム
  • Bun - 高速な起動と実行を提供する新しいランタイム
  • Vercel - サーバーレスプラットフォーム
  • AWS Lambda - サーバーレスコンピューティングサービス
  • Lambda@Edge - Amazonのエッジロケーションでコードを実行
  • Node.js - 従来からの定番サーバーサイドJavaScriptランタイム

各環境での設定例

それぞれの環境でのセットアップ方法を見ていきましょう。

Cloudflare Workers
// src/index.ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => c.text('Hello Cloudflare Workers!'))

// Cloudflare Workersのエントリーポイント
export default app

Cloudflare Workersでの設定(wrangler.toml):

name = "hono-app"
main = "src/index.ts"
compatibility_date = "2025-05-01"

[build]
command = "npm run build"
Deno
// server.ts
import { Hono } from 'https://deno.land/x/hono/mod.ts'
import { serve } from 'https://deno.land/std/http/server.ts'

const app = new Hono()

app.get('/', (c) => c.text('Hello Deno!'))

// Denoでのサーバー起動
serve(app.fetch, { port: 8000 })
Node.js
// src/index.ts
import { Hono } from 'hono'
import { serve } from '@hono/node-server'

const app = new Hono()

app.get('/', (c) => c.text('Hello Node.js!'))

// Node.jsでのサーバー起動
serve({
  fetch: app.fetch,
  port: 3000
})
Bun
// src/index.ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/', (c) => c.text('Hello Bun!'))

// Bunでのサーバー起動
export default {
  port: 3000,
  fetch: app.fetch
}

環境固有の機能の利用

Honoは各環境固有の機能も活用できます。例えば、Cloudflare Workersの場合はKVストアやD1などのサービスを使用できます。

import { Hono } from 'hono'

// 環境変数の型定義
type Bindings = {
  MY_KV: KVNamespace;
  DB: D1Database;
}

// 環境変数の型をジェネリック型として渡す
const app = new Hono<{ Bindings: Bindings }>()

app.get('/kv/:key', async (c) => {
  const key = c.req.param('key')
  // KVストアからデータを取得
  const value = await c.env.MY_KV.get(key)
  
  if (!value) {
    return c.json({ error: 'Key not found' }, 404)
  }
  
  return c.json({ [key]: value })
})

app.get('/db/users', async (c) => {
  // D1データベースからユーザーを取得
  const { results } = await c.env.DB.prepare(
    'SELECT * FROM users LIMIT 10'
  ).all()
  
  return c.json(results)
})

export default app

アダプターを使用した環境間の違いの吸収

Honoはさまざまなランタイム環境の違いを吸収するためのアダプターも提供しています。例えば、静的ファイルの提供やWebSocketの処理などは環境によって異なりますが、アダプターを使うことでこれらの違いを気にせずに開発できます。

import { Hono } from 'hono'
// Cloudflare Workers用のWebSocketアダプター
import { upgradeWebSocket } from 'hono/cloudflare-workers'

const app = new Hono()

// WebSocketエンドポイント
app.get('/ws', upgradeWebSocket((c) => {
  const ws = c.data.webSocket
  
  ws.addEventListener('message', (event) => {
    console.log('受信:', event.data)
    ws.send(`Echo: ${event.data}`)
  })
  
  ws.addEventListener('close', () => {
    console.log('WebSocket接続が閉じられました')
  })
}))

export default app

このように、Honoを使えば、さまざまな環境で一貫したAPIでWebアプリケーションを開発できます。特に、エッジコンピューティングからサーバーレス、従来型のサーバーまで、幅広い選択肢がある現代のWeb開発において、Honoの環境間の移植性は大きな利点となります。

次のセクションでは、HonoXというメタフレームワークを使用して、フルスタックアプリケーションを構築する方法を説明します。

HonoXの基本!メタフレームワークで作るフルスタックアプリ

HonoXは、Honoをベースにしたメタフレームワークです。2025年現在、アルファ版から進化を続けており、フルスタックWebアプリケーション開発のための強力なツールを提供しています。HonoXを使用すると、サーバーサイドレンダリング(SSR)、ファイルベースのルーティング、クライアントサイドハイドレーションなどの機能を簡単に実装できます。

HonoXの特徴

HonoXは以下のような特徴を持っています:

  • ファイルベースのルーティング - Next.jsのように、ファイル構造に基づいたルーティングシステム
  • 高速なSSR - Honoの高速なレンダリング機能を活用
  • BYOR (Bring Your Own Renderer) - hono/jsxに限らず、様々なレンダラーを使用可能
  • アイランドハイドレーション - インタラクティブな要素だけをハイドレーション(部分的なJavaScript読み込み)
  • ミドルウェアサポート - Honoのミドルウェアシステムをそのまま使用可能

HonoXのセットアップ

HonoXプロジェクトを始めるための基本的なセットアップは以下の通りです:

# HonoXアプリの作成
npx create-hono my-honox-app
cd my-honox-app

# 依存関係のインストール
npm install

# 開発サーバーの起動
npm run dev

create-honoコマンドを実行すると、テンプレート選択の選択肢が表示されます。ここで「x-basic」などのHonoXテンプレートを選びます。

プロジェクト構造

HonoXプロジェクトの基本構造は以下のようになります:

my-honox-app/
├── app/
│   ├── routes/
│   │   ├── index.tsx       # ルートページ
│   │   ├── about/
│   │   │   └── index.tsx   # /about ページ
│   │   └── api/
│   │       └── hello.ts    # APIエンドポイント
│   ├── components/         # 共通コンポーネント
│   ├── islands/            # クライアントサイドでハイドレーションされるコンポーネント
│   └── server.ts           # サーバーエントリーポイント
├── package.json
├── tsconfig.json
└── vite.config.ts          # Vite設定

ルーティングの仕組み

HonoXでは、app/routesディレクトリ内のファイル構造に基づいてルーティングが自動的に生成されます。

// app/routes/index.tsx - ルートページ (/)
import { createRoute } from 'honox/factory'

export default createRoute((c) => {
  return c.render(
    <div>
      <h1>ようこそHonoXへ!</h1>
      <p>これはトップページです</p>
    </div>
  )
})
// app/routes/about/index.tsx - アバウトページ (/about)
import { createRoute } from 'honox/factory'

export default createRoute((c) => {
  return c.render(
    <div>
      <h1>アバウトページ</h1>
      <p>HonoXについての説明ページです</p>
    </div>
  )
})

フォームの処理

HonoXではフォーム処理も簡単に実装できます。以下は、フォームからのデータを処理する例です。

// app/routes/contact/index.tsx
import { createRoute } from 'honox/factory'
import { getCookie, setCookie } from 'hono/cookie'

// POSTリクエストのハンドラー
export const POST = createRoute(async (c) => {
  // フォームデータの取得
  const { name, email, message } = await c.req.parseBody<{
    name: string
    email: string
    message: string
  }>()
  
  // 処理ロジック(例:データベースへの保存など)
  console.log('お問い合わせ:', { name, email, message })
  
  // クッキーに保存
  setCookie(c, 'lastContact', new Date().toISOString())
  
  // リダイレクト
  return c.redirect('/contact/thanks')
})

// GETリクエストのハンドラー(フォーム表示)
export default createRoute((c) => {
  const lastContact = getCookie(c, 'lastContact')
  
  return c.render(
    <div>
      <h1>お問い合わせ</h1>
      {lastContact && (
        <p>前回のお問い合わせ: {new Date(lastContact).toLocaleString('ja-JP')}</p>
      )}
      <form method="POST">
        <div>
          <label>
            お名前: <input type="text" name="name" required />
          </label>
        </div>
        <div>
          <label>
            メールアドレス: <input type="email" name="email" required />
          </label>
        </div>
        <div>
          <label>
            メッセージ:
            <textarea name="message" rows={5} required></textarea>
          </label>
        </div>
        <button type="submit">送信</button>
      </form>
    </div>
  )
})

アイランドアーキテクチャ

HonoXはアイランドアーキテクチャをサポートしており、ページの一部だけをクライアントサイドでハイドレーションできます。これにより、JavaScriptの読み込み量を最小限に抑えつつ、必要な部分だけをインタラクティブにできます。

// app/islands/Counter.tsx
import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)
  
  return (
    <div>
      <p>カウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>増加</button>
      <button onClick={() => setCount(count - 1)}>減少</button>
    </div>
  )
}
// app/routes/index.tsx
import { createRoute } from 'honox/factory'
import Counter from '../islands/Counter'

export default createRoute((c) => {
  return c.render(
    <div>
      <h1>アイランドアーキテクチャの例</h1>
      <p>これは静的なテキストです(サーバーサイドレンダリング)</p>
      
      {/* Counterコンポーネントはクライアント側でハイドレーションされる */}
      <Counter />
    </div>
  )
})

APIエンドポイントの作成

HonoXでは、APIエンドポイントの作成も非常に簡単です。

// app/routes/api/users.ts
import { Hono } from 'hono'

// 模擬データ
const users = [
  { id: 1, name: '山田太郎' },
  { id: 2, name: '佐藤花子' }
]

// APIルートの作成
const app = new Hono()

// すべてのユーザーを取得
app.get('/', (c) => {
  return c.json(users)
})

// IDによるユーザー取得
app.get('/:id', (c) => {
  const id = parseInt(c.req.param('id'))
  const user = users.find(u => u.id === id)
  
  if (!user) {
    return c.json({ error: 'ユーザーが見つかりません' }, 404)
  }
  
  return c.json(user)
})

export default app

本番環境へのデプロイ

HonoXアプリケーションは、Cloudflare Pagesなどのプラットフォームに簡単にデプロイできます。

# ビルド
npm run build

# Cloudflare Pagesへのデプロイ(Wranglerを使用)
npx wrangler pages publish dist

HonoXは現在も活発に開発が進められており、今後さらに機能が拡張されていく予定です。フルスタックアプリケーション開発において、Honoの高速さとシンプルさを継承しつつ、より高度な機能を提供するフレームワークとして注目されています。

Honoのベストプラクティスとパフォーマンス最適化テクニック

Honoは最初から高速なパフォーマンスを提供するように設計されていますが、より効率的なアプリケーション開発のためにいくつかのベストプラクティスと最適化テクニックがあります。このセクションでは、Honoアプリケーションを構築する際の重要なプラクティスを紹介します。

プロジェクト構成のベストプラクティス

適切なルーター選択

Honoには複数のルーターが用意されており、用途に応じて選択できます。

import { Hono } from 'hono'
// 特定のルーターを指定する場合
import { Hono } from 'hono/router/reg-exp'
import { Hono } from 'hono/router/smart'
import { Hono } from 'hono/router/linear'
import { Hono } from 'hono/router/pattern'
  • RegExpRouter (デフォルト): 最も高速。すべてのルートパターンを事前に単一の大きな正規表現に変換。
  • SmartRouter: ルートパターンによって異なるルーターを自動的に選択。バランスの取れた選択。
  • LinearRouter: 初期化が非常に速いが、マッチングは線形検索。毎回アプリを初期化する環境に最適。
  • PatternRouter: 最も軽量で単純なルーター。限定的なルートパターンのみサポート。

一般的には、デフォルトのRegExpRouterが最適ですが、アプリケーションの特性に応じて選択すると良いでしょう。

軽量バージョンの使用

アプリケーションサイズが重要な場合は、Honoの軽量バンドルを使用できます:

// 標準版
import { Hono } from 'hono'

// 軽量版(tinyプリセット)- 約12KB
import { Hono } from 'hono/tiny'

パフォーマンス最適化テクニック

コンテキストの効率的な利用

Honoはコンテキスト(c)を使用してリクエスト/レスポンスデータを管理します。コンテキストを効率的に使用することでパフォーマンスを向上できます。

// コンテキストを使用したカスタムデータの保存
app.use('*', async (c, next) => {
  // リクエスト固有のデータを保存
  c.set('startTime', Date.now())
  
  // 特定のデータがある場合のみキャッシュから取得
  if (!c.get('user')) {
    // データベースからユーザー情報を取得
    const user = await getUserFromDb(c.req.header('Authorization'))
    c.set('user', user)
  }
  
  await next()
})
キャッシュ制御の最適化

Honoのキャッシュミドルウェアを活用して、レスポンスのキャッシュを適切に制御できます。

import { Hono } from 'hono'
import { cache } from 'hono/cache'

const app = new Hono()

// 1時間のキャッシュをステートレスなGETリクエストに設定
app.get('/api/products', cache({
  cacheName: 'products-cache',
  cacheControl: 'max-age=3600',
  // 条件付きで使用する場合
  shouldCache: (c) => {
    return c.req.url.includes('/api/products') && !c.req.url.includes('nocache')
  }
}), async (c) => {
  // 製品データを取得(通常は時間がかかる処理)
  const products = await fetchProductsFromDatabase()
  return c.json(products)
})
静的アセットの効率的な配信

静的ファイルの配信を最適化するために、適切なアダプターを使用します。

import { Hono } from 'hono'
import { serveStatic } from 'hono/cloudflare-workers'
// または、環境に応じて別のアダプターを使用
// import { serveStatic } from 'hono/node-server/serve-static'

const app = new Hono()

// 静的ファイルの配信(Cloudflare Workersの場合)
app.get('/static/*', serveStatic({ root: './' }))

// 特定のファイルを配信
app.get('/favicon.ico', serveStatic({ path: './assets/favicon.ico' }))
非同期処理の最適化

非同期処理を効率的に扱うことで、パフォーマンスを向上させることができます。

import { Hono } from 'hono'

const app = new Hono()

app.get('/api/dashboard', async (c) => {
  // Promise.allを使用して並列に複数のデータを取得
  const [userStats, siteStats, recentActivity] = await Promise.all([
    fetchUserStats(),
    fetchSiteStats(),
    fetchRecentActivity()
  ])
  
  return c.json({
    userStats,
    siteStats,
    recentActivity
  })
})

エラーハンドリングのベストプラクティス

適切なエラーハンドリングはアプリケーションの信頼性と品質を高めます。

import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'

const app = new Hono()

// エラーハンドラーの登録
app.onError((err, c) => {
  console.error(`[ERROR] ${err.message}`, err.stack)
  
  // HTTPExceptionの場合は対応するステータスコードを返す
  if (err instanceof HTTPException) {
    return c.json({
      error: err.message,
      code: err.status
    }, err.status)
  }
  
  // その他のエラーは500を返す
  return c.json({
    error: 'サーバー内部エラー',
    code: 500
  }, 500)
})

app.get('/api/secure', async (c) => {
  const user = c.get('user')
  if (!user) {
    // エラーをスローして処理を停止
    throw new HTTPException(401, { message: '認証が必要です' })
  }
  
  // エラー発生時に適切に処理される可能性のある処理
  try {
    const data = await fetchSecureData()
    return c.json(data)
  } catch (err) {
    throw new HTTPException(500, { message: 'データ取得中にエラーが発生しました' })
  }
})

セキュリティのベストプラクティス

Honoアプリケーションのセキュリティを強化するための重要なプラクティス:

import { Hono } from 'hono'
import { secureHeaders } from 'hono/secure-headers'
import { cors } from 'hono/cors'
import { csrf } from 'hono/csrf'

const app = new Hono()

// セキュリティヘッダーを設定
app.use('*', secureHeaders())

// CORSを適切に設定
app.use('*', cors({
  origin: ['https://example.com'],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization'],
  exposeHeaders: ['Content-Length'],
  maxAge: 86400
}))

// CSRFトークンの検証
app.use('/api/*', csrf({
  origin: ['https://example.com']
}))

本番環境へのデプロイに関するベストプラクティス

本番環境へデプロイする際の重要な考慮事項:

  1. 環境変数の使用: 機密情報や環境固有の設定は環境変数として管理。
// 環境変数を型安全に扱う
type Env = {
  Bindings: {
    DATABASE_URL: string;
    API_KEY: string;
    ENVIRONMENT: 'development' | 'production';
  }
}

const app = new Hono<Env>()

app.get('/api/config', (c) => {
  // 環境変数にアクセス
  const environment = c.env.ENVIRONMENT
  
  return c.json({
    env: environment,
    // 機密情報は返さない
    isProduction: environment === 'production'
  })
})
  1. エラーログの適切な処理: 本番環境では詳細なエラー情報をクライアントに返さない。
app.onError((err, c) => {
  // 本番環境とそれ以外で異なる処理
  if (c.env.ENVIRONMENT === 'production') {
    // エラーログを外部サービスに送信
    logErrorToService(err)
    
    // クライアントには最小限の情報のみ返す
    return c.json({ error: 'サーバーエラーが発生しました' }, 500)
  } else {
    // 開発環境ではデバッグ情報を含める
    return c.json({
      error: err.message,
      stack: err.stack
    }, 500)
  }
})
  1. 圧縮の有効化: レスポンスサイズを削減してパフォーマンスを向上。
import { compress } from 'hono/compress'

// 圧縮を有効化
app.use('*', compress())

これらのベストプラクティスとパフォーマンス最適化テクニックを実践することで、Honoアプリケーションの品質、セキュリティ、パフォーマンスを向上させることができます。アプリケーションの具体的な要件に応じて、これらのプラクティスを適切に組み合わせていくことが重要です。

TH

Tasuke Hub管理人

東証プライム市場上場企業エンジニア

情報系修士卒業後、大手IT企業にてフルスタックエンジニアとして活躍。 Webアプリケーション開発からクラウドインフラ構築まで幅広い技術に精通し、 複数のプロジェクトでリードエンジニアを担当。 技術ブログやオープンソースへの貢献を通じて、日本のIT技術コミュニティに積極的に関わっている。

🎓情報系修士🏢東証プライム上場企業💻フルスタックエンジニア📝技術ブログ執筆者

おすすめの書籍

おすすめコンテンツ