Apidog

オールインワン協働API開発プラットフォーム

API設計

APIドキュメント

APIデバッグ

APIモック

API自動テスト

Hono.js入門: 初心者向けガイド

Mark Ponomarev

Mark Ponomarev

Updated on 5月 11, 2025

急速に進化するウェブ開発の世界では、適切なフレームワークを見つけるのは難しい場合があります。高速で軽量、そしてさまざまな環境で柔軟に動作するものが求められます。そこで登場するのがHonoです。その驚異的な速度、最小限のフットプリント、そして開発者に優しい設計により、開発者の間で急速に支持を得ているウェブフレームワークです。

Hono(日本語で「炎」🔥を意味します)は、その名の通り、非常に高速で、エレガントなシンプルさで開発体験を明るく照らします。API、マイクロサービス、フルスタックアプリケーションのいずれを構築する場合でも、Honoはより重いフレームワークに代わる魅力的な選択肢を提供します。

このガイドでは、Hono.jsを始めるために知っておくべきことすべてを、インストールから最初のアプリケーションの構築、そしてそのコアコンセプトの理解まで、順を追って説明します。

💡
美しくAPIドキュメントを生成する素晴らしいAPIテストツールをお探しですか?

最大限の生産性で開発チームが共同作業できる統合されたオールインワンプラットフォームをお探しですか?

Apidogはあなたのすべての要求を満たし、Postmanをはるかに手頃な価格で置き換えます
button

Honoとは?

Honoロゴ

Honoは、Web標準に基づいて構築された、小さくシンプルで超高速なウェブフレームワークです。Cloudflare Workers、Fastly Compute、Deno、Bun、Vercel、Netlify、AWS Lambda、Lambda@Edge、Node.jsなど、事実上あらゆるJavaScriptランタイムで動作します。

Honoの核となるのは、Web標準API(Request、Response、Fetchなど)を採用していることです。これにより、プラットフォーム間での驚くべきポータビリティが実現されています。つまり、一度コードを書けば、大きな変更なしにほぼどこにでもデプロイできるということです。

import { Hono } from 'hono'
const app = new Hono()

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

export default app

この簡単な例は、Expressにインスパイアされつつも、今日のJavaScriptエコシステム向けに近代化されたHonoのクリーンな構文を示しています。

さあ、始めましょう!

1. Bunを使ったHono.jsのインストールとプロジェクトセットアップ

Bunは、その速度と、パッケージマネージャー、バンドラー、テストランナーを含むオールインワンツールキットで知られるモダンなJavaScriptランタイムです。Bunを使ってHonoをセットアップするのは簡単です。

前提条件

Bunがインストールされていることを確認してください。インストールされていない場合は、公式Bunウェブサイトの指示に従ってインストールできます。

Bunで新しいHonoプロジェクトを作成する

Bunで新しいHonoプロジェクトを始める最も簡単な方法は、create-honoスキャフォールディングツールを使うことです。

bun create hono@latest my-hono-app

このコマンドを実行すると、テンプレートを選択するように促されます。このガイドでは、bunテンプレートを選択してください。

? Which template do you want to use? › - Use arrow keys. Return to submit.
❯   bun
    cloudflare-workers
    cloudflare-pages
    deno
    fastly
    netlify
    nodejs
    vercel

テンプレートを選択したら、新しいプロジェクトディレクトリに移動し、依存関係をインストールします。

cd my-hono-app
bun install

既存のBunプロジェクトにHonoを追加する

既存のBunプロジェクトがある場合は、Honoを依存関係として追加できます。

bun add hono

2. Hono.jsを使った基本的なアプリケーションの構築:「Hello Hono!」

簡単な「Hello World」(または「Hello Hono!」)アプリケーションを作成しましょう。

プロジェクト内にsrcディレクトリがあるはずです。src/index.ts(またはプレーンJavaScriptが好みであればindex.jsですが、Honoの利点を最大限に活かすにはTypeScriptが推奨されます)を作成または開きます。

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

const app = new Hono()

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

export default app

これを分解してみましょう。

  1. honoパッケージからHonoクラスをインポートします。
  2. Honoの新しいインスタンスを作成します。通常はappという名前を付けます。
  3. ルートパス(/)へのGETリクエストのルートを定義します。
  4. ルートハンドラーは、Contextオブジェクト(慣習的にc)を引数として取る関数です。
  5. c.text('Hello Hono!')は、プレーンテキスト「Hello Hono!」を含むResponseオブジェクトを作成します。
  6. 最後に、appインスタンスをエクスポートします。Bunの場合、このデフォルトエクスポートは開発サーバーがそれを認識するのに十分です。

アプリケーションを実行する

開発モードでアプリケーションを実行するには、package.jsonに定義されているdevスクリプトを使用します(create-honoが設定してくれます)。

bun run dev

これにより、通常はhttp://localhost:3000でサーバーが起動します。ウェブブラウザでこのURLを開くと、「Hello Hono!」と表示されるはずです。

ポートを変更する

アプリケーションを別のポートで実行する必要がある場合は、src/index.tsのエクスポートを変更できます。

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

const app = new Hono()

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

export default {
  port: 8080, // 希望するポートを指定
  fetch: app.fetch,
}

これで、bun run devを実行すると、アプリケーションはhttp://localhost:8080で提供されます。

3. Hono.jsを使った基本的なAPIの構築

HonoはAPIの構築に優れています。ルーティング、リクエストの処理、レスポンスの作成方法を見ていきましょう。

ルーティング

Honoでのルーティングは直感的です。appインスタンスには、HTTP動詞に対応するメソッドがあります(.get().post().put().delete()など)。

基本的なGETルート

基本的なGETルートはすでに見てきました。

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

パスパラメータ

:paramName構文を使用して、パスパラメータを持つルートを定義できます。これらのパラメータはc.req.param('paramName')経由でアクセスできます。

// 例: /users/123
app.get('/users/:id', (c) => {
  const userId = c.req.param('id')
  return c.text(`User ID: ${userId}`)
})

クエリパラメータ

URLからのクエリパラメータ(例: /search?q=hono)は、c.req.query('queryName')を使用してアクセスできます。

// 例: /search?category=frameworks&limit=10
app.get('/search', (c) => {
  const category = c.req.query('category')
  const limit = c.req.query('limit')
  return c.text(`Searching in category: ${category}, Limit: ${limit}`)
})

c.req.query()ですべてのクエリパラメータをオブジェクトとして取得することもできます。

異なるHTTPメソッドの処理

Honoでは、同じパスに対して様々なHTTPメソッドを簡単に処理できます。

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

const app = new Hono()

// 投稿リストを取得 (GET)
app.get('/posts', (c) => {
  // 実際のアプリでは、データベースから取得します
  const posts = [
    { id: '1', title: 'Getting Started with Hono' },
    { id: '2', title: 'Advanced Hono Techniques' },
  ];
  return c.json(posts); // JSONレスポンスを返す
})

// IDで単一の投稿を取得 (GET)
app.get('/posts/:id', (c) => {
  const id = c.req.param('id')
  // データベースからIDで投稿を取得
  const post = { id: id, title: `Post ${id}`, content: 'This is the content...' };
  if (!post) {
    return c.notFound() // 404のための組み込みヘルパー
  }
  return c.json(post)
})

// 新しい投稿を作成 (CREATE)
app.post('/posts', async (c) => {
  const body = await c.req.json() // JSONボディをパース
  // 実際のアプリでは、これをデータベースに保存します
  console.log('Creating post:', body)
  return c.json({ message: 'Post created successfully!', data: body }, 201) // 201 Createdで応答
})

// 既存の投稿を更新 (UPDATE)
app.put('/posts/:id', async (c) => {
  const id = c.req.param('id')
  const body = await c.req.json()
  // データベースで投稿を更新
  console.log(`Updating post ${id}:`, body)
  return c.json({ message: `Post ${id} updated successfully!`, data: body })
})

// 投稿を削除 (DELETE)
app.delete('/posts/:id', (c) => {
  const id = c.req.param('id')
  // データベースから投稿を削除
  console.log(`Deleting post ${id}`)
  return c.json({ message: `Post ${id} deleted successfully!` })
})


export default {
  port: 3000,
  fetch: app.fetch
}

リクエストオブジェクト(c.req

Contextオブジェクト(c)は、c.reqを介してリクエストの詳細へのアクセスを提供します。主なプロパティとメソッドは以下の通りです。

  • c.req.url: 完全なURL文字列。
  • c.req.method: HTTPメソッド(例: 'GET', 'POST')。
  • c.req.headers: Headersオブジェクト。c.req.header('Content-Type')のようにヘッダーにアクセスします。
  • c.req.param('name'): パスパラメータを取得します。
  • c.req.query('name'): クエリパラメータを取得します。
  • c.req.queries('name'): 繰り返し出現するクエリパラメータのすべての値を配列として取得します。
  • c.req.json(): リクエストボディをJSONとしてパースします。(Promiseを返します)
  • c.req.text(): リクエストボディをプレーンテキストとして読み取ります。(Promiseを返します)
  • c.req.arrayBuffer(): リクエストボディをArrayBufferとして読み取ります。(Promiseを返します)
  • c.req.formData(): リクエストボディをFormDataとしてパースします。(Promiseを返します)
  • c.req.valid('type'): バリデーション済みデータにアクセスします(バリデーターと組み合わせて使用、後述)。

レスポンスオブジェクト(c)とヘルパー

Contextオブジェクト(c)は、Responseオブジェクトを作成するための便利なヘルパーも提供します。

  • c.text(text, status?, headers?): プレーンテキストレスポンスを返します。
  • c.json(object, status?, headers?): JSONレスポンスを返します。Content-Typeは自動的にapplication/jsonに設定されます。
  • c.html(html, status?, headers?): HTMLレスポンスを返します。
  • c.redirect(location, status?): リダイレクトレスポンスを返します(デフォルトステータス302)。
  • c.notFound(): 404 Not Foundレスポンスを返します。
  • c.newResponse(body, status?, headers?): 新しいResponseオブジェクトを作成します。bodynullReadableStreamArrayBufferFormDataURLSearchParams、またはstringにすることができます。
  • c.header(name, value): レスポンスヘッダーを設定します。

例:カスタムヘッダーの設定

app.get('/custom-header', (c) => {
  c.header('X-Powered-By', 'HonoJS-Flame')
  c.header('Cache-Control', 'no-cache')
  return c.text('Check the response headers!')
})

4. Hono.jsでのミドルウェアの操作

ミドルウェア関数は、Hono(および多くのウェブフレームワーク)の基盤です。これらは、リクエストがメインのルートハンドラーに到達する前に処理したり、ハンドラーが実行された後にレスポンスを処理したりできる関数です。ミドルウェアは、ロギング、認証、データ検証、圧縮、CORSなどに非常に役立ちます。

ミドルウェア関数の基本的なシグネチャはasync (c, next) => { ... }です。

  • c: Contextオブジェクト。
  • next: チェーン内の次のミドルウェア、または最終的なルートハンドラーに制御を渡すために呼び出す関数。後続のミドルウェアまたはハンドラーを実行したい場合は、await next()を**必ず**呼び出す必要があります。

組み込みミドルウェアの使用

Honoには豊富な組み込みミドルウェアセットが付属しています。これらはhono/middleware-nameからインポートできます(例: hono/loggerhono/cors)。

すべてのルートにミドルウェアを適用するには、app.use(middlewareFunction)を使用します。
特定のルートにミドルウェアを適用するには、最初の引数としてパスパターンを指定します:app.use('/admin/*', authMiddleware)

例:LoggerとETagミドルウェア

// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { etag } from 'hono/etag'
import { prettyJSON } from 'hono/pretty-json' // JSONレスポンスをきれいに整形するため

const app = new Hono()

// すべてのルートにミドルウェアを適用
app.use(logger()) // リクエストとレスポンスの情報をコンソールにログ出力
app.use(etag())   // キャッシュのためにETagヘッダーを追加
app.use(prettyJSON()) // JSONレスポンスをインデント付きで整形

app.get('/', (c) => {
  return c.text('Hello with Logger and ETag!')
})

app.get('/data', (c) => {
  return c.json({ message: 'This is some data.', timestamp: Date.now() })
})

export default app

これを実行して/または/dataにアクセスすると、コンソールにログが表示され、レスポンスにはETagヘッダーが含まれます。/dataからのJSONレスポンスはきれいに整形されます。

その他の便利な組み込みミドルウェア:

  • cors: クロスオリジンリソース共有を処理します。
  • basicAuth: Basic認証を実装します。
  • jwt: JWT(JSON Web Token)認証。
  • compress: レスポンスボディを圧縮します。
  • cache: Cache APIを使用してキャッシュを実装します。
  • secureHeaders: 様々なセキュリティ関連のHTTPヘッダーを追加します。
  • bodyLimit: リクエストボディのサイズを制限します。

完全なリストとドキュメントは、Honoドキュメントの「Middleware」セクションにあります。

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

独自のミドルウェアを簡単に書くことができます。

例1:シンプルなリクエストタイマー

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

const app = new Hono()

app.use(logger())

// リクエスト処理時間を計測するカスタムミドルウェア
app.use(async (c, next) => {
  const start = Date.now()
  console.log(`Request received at: ${new Date(start).toISOString()}`)
  await next() // 次のミドルウェアまたはルートハンドラーを呼び出す
  const ms = Date.now() - start
  c.header('X-Response-Time', `${ms}ms`) // レスポンスにカスタムヘッダーを追加
  console.log(`Request processed in ${ms}ms`)
})

app.get('/', (c) => {
  return c.text('Hello from Hono with custom timing middleware!')
})

app.get('/slow', async (c) => {
  // 遅い操作をシミュレート
  await new Promise(resolve => setTimeout(resolve, 1500))
  return c.text('This was a slow response.')
})

export default app

//slowにアクセスして、タイミングログとX-Response-Timeヘッダーを確認してください。

例2:シンプルなAPIキー認証ミドルウェア

これはデモンストレーションのための非常に基本的な例です。実際のアプリケーションでは、JWTやOAuthのようなより堅牢な認証方法を使用し、APIキーは安全に保存してください。

// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { HTTPException } from 'hono/http-exception' // 標準的なHTTPエラーをスローするため

const app = new Hono()

app.use(logger())

const API_KEY = "supersecretapikey"; // 実際のアプリでは、これを安全に保存します(例: 環境変数)

// カスタムAPIキー認証ミドルウェア
const apiKeyAuth = async (c, next) => {
  const apiKeyHeader = c.req.header('X-API-KEY')
  if (apiKeyHeader && apiKeyHeader === API_KEY) {
    await next()
  } else {
    // HTTPExceptionを使用して標準化されたエラーレスポンスを返す
    throw new HTTPException(401, { message: 'Unauthorized: Invalid API Key' })
  }
}

// このミドルウェアを特定のルートグループに適用
app.use('/api/v1/*', apiKeyAuth)

app.get('/api/v1/me', (c) => {
  return c.json({ user: 'Authenticated User', email: 'user@example.com' })
})

app.get('/public/info', (c) => {
  return c.text('This is public information, no API key needed.')
})

// HTTPExceptionのためのエラーハンドラー
app.onError((err, c) => {
  if (err instanceof HTTPException) {
    return err.getResponse()
  }
  // その他のエラーの場合
  console.error('Unhandled error:', err)
  return c.text('Internal Server Error', 500)
})


export default app

これをテストするには:

  • curl http://localhost:3000/api/v1/me (401 Unauthorizedが返されるはずです)
  • curl -H "X-API-KEY: supersecretapikey" http://localhost:3000/api/v1/me (ユーザーデータが返されるはずです)
  • curl http://localhost:3000/public/info (公開情報が返されるはずです)

createMiddlewareを使ったカスタムミドルウェアの再利用

より複雑な、または再利用可能なミドルウェアの場合、hono/factoryからcreateMiddlewareを使用して別途定義できます。これはTypeScriptの型推論にも役立ちます。

// src/middlewares/timing.ts
import { createMiddleware } from 'hono/factory'

export const timingMiddleware = createMiddleware(async (c, next) => {
  const start = Date.now()
  await next()
  const ms = Date.now() - start
  c.res.headers.set('X-Response-Time', `${ms}ms`) // Note: c.res.headers.set
  console.log(` -> Processed in ${ms}ms`)
})

// src/middlewares/auth.ts
import { createMiddleware } from 'hono/factory'
import { HTTPException } from 'hono/http-exception'

const VALID_API_KEY = "anothersecretkey";

// ミドルウェアが環境変数を必要とする場合の型
type Env = {
  Variables: {
    user?: { id: string } // 例: 認証後にユーザーデータを設定
  }
  // Bindings: { MY_KV_NAMESPACE: KVNamespace } // Cloudflare Workersの例
}

export const secureApiKeyAuth = createMiddleware<Env>(async (c, next) => {
  const apiKey = c.req.header('Authorization')?.replace('Bearer ', '')
  if (apiKey === VALID_API_KEY) {
    // オプションで、後続のハンドラーのためにコンテキストに変数を設定できます
    c.set('user', { id: 'user123' })
    await next()
  } else {
    throw new HTTPException(401, { message: 'Access Denied: Secure API Key Required.'})
  }
})


// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { timingMiddleware } from './middlewares/timing' // middlewaresフォルダにあると仮定
import { secureApiKeyAuth } from './middlewares/auth'

const app = new Hono()

app.use(logger())
app.use(timingMiddleware) // すべてのルートに適用

app.get('/', (c) => {
  return c.text('Hello from Hono with factored middleware!')
})

app.use('/secure/data/*', secureApiKeyAuth) // /secure/data/*にのみ適用
app.get('/secure/data/profile', (c) => {
  // const user = c.get('user') // ミドルウェアによって設定された変数にアクセス
  return c.json({ profileData: 'Sensitive profile information', /*user: user*/ })
})

app.get('/public/data', (c) => {
  return c.text('This is public data, no key needed.')
})

// 一般的なエラーハンドラー
app.onError((err, c) => {
  if (err instanceof HTTPException) {
    return err.getResponse();
  }
  console.error('Error:', err.message);
  return c.json({ error: 'Internal Server Error', message: err.message }, 500);
});

export default app

この構造により、ミドルウェアがよりモジュール化され、独立してテストしやすくなります。

5. Hono.jsアプリケーションのテスト

Honoは簡単にテストできるように設計されています。Bunには独自のテストランナーbun:testが付属しており、Honoとうまく連携します。Vitestのような他のテストランナーを使用することもできます。

bun:testの使用(基本)

bun.mdドキュメントには、bun:testを使ったテストの基本的な例が記載されています。

例えば、src/index.test.tsというテストファイルを作成します。

// src/index.test.ts
import { describe, expect, it } from 'bun:test'
import app from '.' // src/index.tsからアプリをインポート

describe('Hono Application Tests', () => {
  it('Should return 200 OK for GET /', async () => {
    const req = new Request('http://localhost/') // ここではベースURLはあまり重要ではありません
    const res = await app.fetch(req)
    expect(res.status).toBe(200)
    expect(await res.text()).toBe('Hello Hono!') // またはルートルートが返すもの
  })

  it('Should return JSON for GET /posts', async () => {
    const req = new Request('http://localhost/posts')
    const res = await app.fetch(req)
    expect(res.status).toBe(200)
    const json = await res.json()
    expect(json).toBeArray() // /postsが配列を返すと仮定
    // 必要に応じてJSONコンテンツに関するより具体的なアサーションを追加
  })

  it('Should create a post for POST /posts', async () => {
    const postData = { title: 'Test Post', content: 'This is a test.' };
    const req = new Request('http://localhost/posts', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(postData),
    });
    const res = await app.fetch(req);
    expect(res.status).toBe(201); // 201 Createdを期待
    const jsonResponse = await res.json();
    expect(jsonResponse.message).toBe('Post created successfully!');
    expect(jsonResponse.data.title).toBe(postData.title);
  });
})

テストを実行するには:

bun test

または、特定のファイルを実行したい場合:

bun test src/index.test.ts

app.request()ヘルパーの使用

Honoは便利なapp.request()メソッドを提供しており、これにより毎回完全なRequestオブジェクトを構築する代わりに、パスとオプションを直接渡すことでテストを簡素化できます。これはdocs/guides/testing.mdに示されています。

// src/index.test.ts
import { describe, expect, it } from 'bun:test' // または 'vitest' からインポート
import app from '.' // Honoアプリインスタンス

describe('Hono App with app.request()', () => {
  it('GET / should return "Hello Hono!"', async () => {
    const res = await app.request('/')
    expect(res.status).toBe(200)
    expect(await res.text()).toBe('Hello Hono!') // 実際のルートレスポンスに合わせて調整
  })

  it('GET /posts/:id should return a specific post', async () => {
    // アプリに app.get('/posts/:id', ...) のようなルートがあると仮定
    // そしてこのテストでは { id: '123', title: 'Test Post 123' } を返すかもしれない
    const res = await app.request('/posts/123')
    expect(res.status).toBe(200)
    const data = await res.json()
    expect(data.id).toBe('123')
    // expect(data.title).toBe('Post 123') // またはアプリのロジックに基づく
  })

  it('POST /posts should create a new post', async () => {
    const newPost = { title: 'My New Post', content: 'Awesome content here.' }
    const res = await app.request('/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(newPost),
    })
    expect(res.status).toBe(201) // POST /posts が 201 を返すと仮定
    const responseData = await res.json()
    expect(responseData.message).toBe('Post created successfully!')
    expect(responseData.data.title).toBe(newPost.title)
  })

  it('GET /api/v1/me without API key should be 401', async () => {
    // 先の例のAPIキーミドルウェアがこのルートでアクティブであると仮定
    const res = await app.request('/api/v1/me')
    expect(res.status).toBe(401)
  })

  it('GET /api/v1/me with correct API key should be 200', async () => {
    const res = await app.request('/api/v1/me', {
      headers: {
        'X-API-KEY': 'supersecretapikey' // ミドルウェアのキーを使用
      }
    })
    expect(res.status).toBe(200)
    const data = await res.json();
    expect(data.user).toBe('Authenticated User')
  })
})

型安全なテストのためのtestClient()ヘルパーの使用

さらに優れた型安全性を実現するために、特にHonoのRPC機能を使用している場合や、明確に定義されたルートスキーマがある場合は、HonoはtestClientヘルパー(hono/testingから)を提供します。このクライアントは、Honoアプリケーションのルートに基づいて型付けされており、テストでオートコンプリートと型チェックを提供します。

testClientの型推論に関する重要な注意:
testClientが型を正しく推論するためには、**Honoインスタンスに直接チェーンメソッドを使用してルートを定義する**必要があります(例:const app = new Hono().get(...).post(...))。または、RPCを使用している場合はルート型をエクスポートする必要があります。ルートを別途定義している場合(例:const app = new Hono(); app.get(...))、testClientの型推論は制限される可能性があります。

// src/app-for-test-client.ts
// testClientをデモンストレーションするために、チェーンされたルートを持つアプリを定義しましょう
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator' // 型付きクエリパラメータの例
import { z } from 'zod'

const appWithChainedRoutes = new Hono()
  .get('/search',
    zValidator('query', z.object({ q: z.string(), limit: z.coerce.number().optional() })),
    (c) => {
      const { q, limit } = c.req.valid('query')
      return c.json({ query: q, limit: limit || 10, results: [`result for ${q} 1`, `result for ${q} 2`] })
    }
  )
  .post('/submit',
    zValidator('json', z.object({ name: z.string(), email: z.string().email() })),
    async (c) => {
      const data = c.req.valid('json')
      return c.json({ message: `Received data for ${data.name}`, data }, 201)
    }
  );

export default appWithChainedRoutes;


// src/app-for-test-client.test.ts
import { describe, expect, it } from 'bun:test'
import { testClient } from 'hono/testing'
import appWithChainedRoutes from './app-for-test-client' // アプリをインポート

describe('Hono App with testClient', () => {
  const client = testClient(appWithChainedRoutes)

  it('GET /search should return typed results', async () => {
    const res = await client.search.$get({
      query: { q: 'hono rocks' }
    })
    expect(res.status).toBe(200)
    const data = await res.json()
    expect(data.query).toBe('hono rocks')
    expect(data.results.length).toBeGreaterThan(0)
  })

  it('GET /search with limit should respect it', async () => {
    const res = await client.search.$get({
      query: { q: 'hono with limit', limit: '5' } // クエリパラメータは最初は文字列
    })
    expect(res.status).toBe(200)
    const data = await res.json()
    expect(data.limit).toBe(5) // Zodバリデーターが数値に強制変換した
  })

  it('POST /submit should accept valid data', async () => {
    const payload = { name: 'Test User', email: 'test@example.com' }
    // JSONボディを持つPOST、PUTなどの場合、client.path.$post({ json: payload }) となります
    const res = await client.submit.$post({
      json: payload
    })
    expect(res.status).toBe(201)
    const data = await res.json()
    expect(data.message).toBe(`Received data for ${payload.name}`)
    expect(data.data.email).toBe(payload.email)
  });

  it('POST /submit with headers', async () => {
    const payload = { name: 'Test User Headers', email: 'testheaders@example.com' }
    const res = await client.submit.$post({
      json: payload
    }, {
      headers: {
        'X-Custom-Test-Header': 'Testing123'
      }
    })
    expect(res.status).toBe(201)
    // 通常、このヘッダーを読み取って検証するルート/ミドルウェアがあるはずです
  });
})

このテストを実行するには、@hono/zod-validatorzodがインストールされていると仮定して(bun add @hono/zod-validator zod):

bun test src/app-for-test-client.test.ts

このtestClientは、特に定義されたスキーマを持つAPIのテストにおいて、はるかに優れた開発体験を提供します。

結論

Honoは、速度、軽量設計、そして開発者に優しい機能の組み合わせにより、ウェブ開発への新鮮なアプローチを提供します。このガイドでは、始めるための基本を網羅しましたが、さらに探求すべきことはたくさんあります。

  • 高度なルーティング技術
  • より複雑なミドルウェアパターン
  • JSXを使ったサーバーサイドレンダリング
  • データベースとの統合
  • Hono Clientを使った型安全なRPCスタイルのAPI
  • 様々なプラットフォームへのデプロイ

Honoを使った旅を続けるにあたっては、より詳細な情報やインスピレーションを得るために、公式ドキュメントexamplesリポジトリを参照してください。

ウェブ開発の状況は常に進化しており、HonoはWeb標準を採用し、パフォーマンスを優先し、成長するJavaScriptランタイムのエコシステム全体で動作するモダンなアプローチを代表しています。シンプルなAPIを構築する場合でも、複雑なアプリケーションを構築する場合でも、Honoは不要なオーバーヘッドなしに必要なツールを提供します。

小さく始めて、実験し、あなたのアプリケーションがHonoと共に成長するのを見てください。その炎のような名前にふさわしい、軽量で超高速なウェブフレームワークです。🔥

💡
美しくAPIドキュメントを生成する素晴らしいAPIテストツールをお探しですか?

最大限の生産性で開発チームが共同作業できる統合されたオールインワンプラットフォームをお探しですか?

Apidogはあなたのすべての要求を満たし、Postmanをはるかに手頃な価格で置き換えます
button