mcpField
H
hono-core

hono-core

github.com/bobmatnyc開発78490 回インストール15 週間前に更新
リポジトリ

hono-core について

Honoは、エッジ、サーバーレスなど複数のランタイムでAPIを構築する開発者向けのTypeScript中心のWebフレームワークです。Web標準APIを基盤とし、型付きルーティングとミドルウェアを提供します。

主な機能

  1. 01Web標準ベースのAPI
  2. 02マルチランタイム対応
  3. 03高速なRegExpRouterルーティング
  4. 04TypeScriptの型推論
  5. 05ミドルウェアエコシステム

活用シーン

  1. 01エッジ環境向けAPIの構築
  2. 02複数ランタイムで同じコードベースを実行
  3. 03型付きHTTPルートの作成
  4. 04CORS、認証、圧縮の追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill hono-core

インストール後、Claude Code で/hono-coreを入力して読み込まれたか確認します。

同梱ファイルmetadata.json

詳細

Hono - 超高速 Web フレームワーク

概要

Hono は、Web 標準に基づいて構築された、小さくシンプルで超高速な Web フレームワークです。同じコードベースで Cloudflare Workers、Deno、Bun、Node.js などで動作します。名前は日本語で「炎」を意味します。

主な機能:

  • Web 標準(Request/Response/fetch)に基づいて構築
  • マルチランタイム:Cloudflare Workers、Deno、Bun、Node.js、Vercel、AWS Lambda
  • RegExpRouter による超高速ルーティング
  • TypeScript を第一級でサポート
  • 軽量(圧縮後約 14KB)
  • 豊富なミドルウェアエコシステム

インストール:

# Create new project (recommended)
npm create hono@latest my-app

# Or install in existing project
npm install hono

# Runtime-specific adapters
npm install @hono/node-server  # Node.js

このスキルを使う場面

次のような場合に Hono を使用します:

  • エッジ/サーバーレス環境(Cloudflare Workers、Vercel Edge)向けの API を構築する
  • マルチランタイム間の移植性が必要(Bun、Deno、Node.js で同じコードを使用)
  • 優れた型推論を備えた TypeScript 中心の開発を行いたい
  • 軽量で高性能な API を構築する
  • 一般的なパターン(CORS、認証、圧縮)に対応する組み込みミドルウェアが必要

Hono とその他のフレームワークの比較:

  • Hono:マルチランタイム、Web 標準、超高速、エッジ向けに最適化
  • Express:Node.js 専用、より大きなエコシステム、低速
  • Fastify:Node.js 専用、スキーマベース、高いパフォーマンス
  • Elysia:Bun 専用、優れたパフォーマンス、異なる API スタイル

コアコンセプト

アプリケーションの作成
import { Hono } from 'hono'

const app = new Hono()

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

export default app

TypeScript のジェネリクスを使用する場合(バインディング/変数用):

type Bindings = {
  DATABASE_URL: string
  API_KEY: string
}

type Variables = {
  user: { id: string; name: string }
}

const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()
コンテキストオブジェクト(c)

コンテキスト c から、リクエストデータとレスポンスメソッドにアクセスできます:

app.get('/users/:id', async (c) => {
  // Request data
  const id = c.req.param('id')           // Path parameter
  const query = c.req.query('sort')       // Query parameter ?sort=asc
  const queries = c.req.queries('tags')   // Multiple: ?tags=a&tags=b
  const header = c.req.header('Authorization')
  const body = await c.req.json()         // JSON body
  const form = await c.req.formData()     // Form data

  // Environment (Cloudflare Workers bindings)
  const db = c.env.DATABASE_URL

  // Custom variables (set by middleware)
  const user = c.get('user')

  // Response methods
  return c.text('Plain text')
  return c.json({ id, name: 'User' })
  return c.html('<h1>Hello</h1>')
  return c.redirect('/login')
  return c.notFound()
})
レスポンスメソッド
// Text response
c.text('Hello', 200)

// JSON response
c.json({ message: 'Success' }, 201)
c.json({ error: 'Not found' }, 404)

// HTML response
c.html('<h1>Hello</h1>')

// Redirect
c.redirect('/login')           // 302 default
c.redirect('/login', 301)      // Permanent redirect

// Headers
c.header('X-Custom', 'value')
c.header('Cache-Control', 'max-age=3600')

// Streaming
c.streamText(async (stream) => {
  await stream.write('Hello ')
  await stream.write('World!')
})

// Raw Response
return new Response('Raw', { status: 200 })

ルーティングパターン

基本的なルーティング
const app = new Hono()

// HTTP methods
app.get('/users', getUsers)
app.post('/users', createUser)
app.put('/users/:id', updateUser)
app.delete('/users/:id', deleteUser)
app.patch('/users/:id', patchUser)

// All methods
app.all('/webhook', handleWebhook)

// Custom methods
app.on('PURGE', '/cache', purgeCache)
app.on(['GET', 'POST'], '/form', handleForm)
パスパラメーター
// Single parameter
app.get('/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id })
})

// Multiple parameters
app.get('/posts/:postId/comments/:commentId', (c) => {
  const { postId, commentId } = c.req.param()
  return c.json({ postId, commentId })
})

// Optional parameter
app.get('/api/animal/:type?', (c) => {
  const type = c.req.param('type') || 'all'
  return c.json({ type })
})

// Regex validation
app.get('/posts/:id{[0-9]+}', (c) => {
  const id = c.req.param('id')  // Only numeric IDs
  return c.json({ id })
})

// Wildcards
app.get('/files/*', (c) => {
  const path = c.req.param('*')  // Everything after /files/
  return c.text(`File: ${path}`)
})
ルートのグループ化
// Using app.route()
const api = new Hono()
api.get('/users', getUsers)
api.get('/posts', getPosts)

const app = new Hono()
app.route('/api/v1', api)  // /api/v1/users, /api/v1/posts

// Using basePath()
const v2 = new Hono().basePath('/api/v2')
v2.get('/users', getUsers)  // /api/v2/users

// Chaining
app
  .get('/a', handlerA)
  .post('/b', handlerB)
  .delete('/c', handlerC)
ルートの整理(複数ファイル)
// routes/users.ts
import { Hono } from 'hono'

const users = new Hono()

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

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

users.get('/:id', async (c) => {
  const id = c.req.param('id')
  return c.json({ id })
})

export default users

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

const app = new Hono()

app.route('/users', users)
app.route('/posts', posts)

export default app

ハンドラーパターン

インラインハンドラー
// Simple handler
app.get('/hello', (c) => c.text('Hello!'))

// Async handler
app.get('/users', async (c) => {
  const users = await fetchUsers()
  return c.json({ users })
})

// Multiple handlers (middleware chain)
app.get('/admin', authenticate, authorize, (c) => {
  return c.json({ admin: true })
})
ファクトリーを使用した型安全なハンドラー
import { createFactory } from 'hono/factory'

const factory = createFactory<{ Bindings: Bindings }>()

// Create typed handler
const getUser = factory.createHandlers(async (c) => {
  const id = c.req.param('id')
  const db = c.env.DATABASE_URL  // Typed!
  return c.json({ id })
})

app.get('/users/:id', ...getUser)

エラー処理

組み込みのエラー処理
import { HTTPException } from 'hono/http-exception'

app.get('/users/:id', async (c) => {
  const user = await findUser(c.req.param('id'))

  if (!user) {
    throw new HTTPException(404, { message: 'User not found' })
  }

  return c.json(user)
})

// Global error handler
app.onError((err, c) => {
  console.error(`${err}`)

  if (err instanceof HTTPException) {
    return err.getResponse()
  }

  return c.json({ error: 'Internal Server Error' }, 500)
})

// Not found handler
app.notFound((c) => {
  return c.json({ error: 'Route not found' }, 404)
})
カスタムエラークラス
class ValidationError extends HTTPException {
  constructor(errors: string[]) {
    super(400, {
      message: 'Validation failed',
      cause: errors
    })
  }
}

class AuthenticationError extends HTTPException {
  constructor() {
    super(401, { message: 'Authentication required' })
  }
}

ランタイム固有のエクスポート

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

const app = new Hono()
app.get('/', (c) => c.text('Hello Cloudflare!'))

export default app
Node.js
// src/index.ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'

const app = new Hono()
app.get('/', (c) => c.text('Hello Node!'))

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!'))

export default {
  port: 3000,
  fetch: app.fetch
}
Deno
// main.ts
import { Hono } from 'npm:hono'

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

Deno.serve(app.fetch)

ベストプラクティス

ハンドラーはインラインで記述する(コントローラーは使わない)
// CORRECT: Inline handlers with proper type inference
app.get('/users/:id', async (c) => {
  const id = c.req.param('id')  // Type: string
  return c.json({ id })
})

// AVOID: Controller-style (loses type inference)
class UserController {
  getUser(c: Context) {
    const id = c.req.param('id')  // Type: string | undefined
    return c.json({ id })
  }
}
モジュール化されたルートを使用する
// CORRECT: Split routes by domain
// routes/users.ts
export const users = new Hono()
  .get('/', listUsers)
  .post('/', createUser)
  .get('/:id', getUser)

// app.ts
app.route('/users', users)
すべてに型を付ける
// Define your environment bindings
type Bindings = {
  DATABASE_URL: string
  JWT_SECRET: string
  MY_KV: KVNamespace
}

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

// Now c.env is fully typed
app.get('/', (c) => {
  const url = c.env.DATABASE_URL  // string
  const kv = c.env.MY_KV          // KVNamespace
})

クイックリファレンス

よく使うコンテキストメソッド
メソッド説明例
c.req.param(name)パスパラメーターを取得c.req.param('id')
c.req.query(name)クエリパラメーターを取得c.req.query('page')
c.req.header(name)リクエストヘッダーを取得c.req.header('Authorization')
c.req.json()JSON ボディを解析await c.req.json()
c.req.formData()フォームデータを解析await c.req.formData()
c.text(str, status)テキストレスポンスc.text('OK', 200)
c.json(obj, status)JSON レスポンスc.json({}, 201)
c.html(str)HTML レスポンスc.html('<h1>Hi</h1>')
c.redirect(url)リダイレクトc.redirect('/login')
c.header(k, v)レスポンスヘッダーを設定c.header('X-Custom', 'val')
c.set(key, val)コンテキスト変数を設定c.set('user', user)
c.get(key)コンテキスト変数を取得c.get('user')
c.env環境バインディングc.env.API_KEY
HTTP メソッド
app.get(path, ...handlers)
app.post(path, ...handlers)
app.put(path, ...handlers)
app.delete(path, ...handlers)
app.patch(path, ...handlers)
app.options(path, ...handlers)
app.head(path, ...handlers)
app.all(path, ...handlers)
app.on(method, path, ...handlers)

関連スキル

  • hono-middleware - ミドルウェアのパターンと合成
  • hono-validation - Zod によるリクエスト検証
  • hono-rpc - 型安全な RPC クライアント
  • hono-testing - テストのパターン
  • hono-jsx - サーバーサイドの JSX レンダリング
  • hono-cloudflare - Cloudflare Workers へのデプロイ

バージョン:Hono 4.x 最終更新日:2025年1月 ライセンス:MIT

コメント