急速に進化するウェブ開発の世界では、適切なフレームワークを見つけるのは難しい場合があります。高速で軽量、そしてさまざまな環境で柔軟に動作するものが求められます。そこで登場するのがHonoです。その驚異的な速度、最小限のフットプリント、そして開発者に優しい設計により、開発者の間で急速に支持を得ているウェブフレームワークです。
Hono(日本語で「炎」🔥を意味します)は、その名の通り、非常に高速で、エレガントなシンプルさで開発体験を明るく照らします。API、マイクロサービス、フルスタックアプリケーションのいずれを構築する場合でも、Honoはより重いフレームワークに代わる魅力的な選択肢を提供します。
このガイドでは、Hono.jsを始めるために知っておくべきことすべてを、インストールから最初のアプリケーションの構築、そしてそのコアコンセプトの理解まで、順を追って説明します。
最大限の生産性で開発チームが共同作業できる統合されたオールインワンプラットフォームをお探しですか?
Apidogはあなたのすべての要求を満たし、Postmanをはるかに手頃な価格で置き換えます!
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
これを分解してみましょう。
hono
パッケージからHono
クラスをインポートします。Hono
の新しいインスタンスを作成します。通常はapp
という名前を付けます。- ルートパス(
/
)へのGET
リクエストのルートを定義します。 - ルートハンドラーは、
Context
オブジェクト(慣習的にc
)を引数として取る関数です。 c.text('Hello Hono!')
は、プレーンテキスト「Hello Hono!」を含むResponse
オブジェクトを作成します。- 最後に、
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
オブジェクトを作成します。body
はnull
、ReadableStream
、ArrayBuffer
、FormData
、URLSearchParams
、または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/logger
、hono/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-validator
とzod
がインストールされていると仮定して(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と共に成長するのを見てください。その炎のような名前にふさわしい、軽量で超高速なウェブフレームワークです。🔥
最大限の生産性で開発チームが共同作業できる統合されたオールインワンプラットフォームをお探しですか?
Apidogはあなたのすべての要求を満たし、Postmanをはるかに手頃な価格で置き換えます!