fastify-v5 について
Fastify v5 と TypeScript を使う開発者向けの実践ガイドです。TypeBox による型安全なルート、OpenAPI 生成、プラグイン、フック、inject() によるテストを扱います。
主な機能
- 01TypeBox でリクエストとレスポンスのスキーマを定義
- 02スキーマからルート型を推論
- 03スキーマから OpenAPI を生成
- 04プラグインとリクエストフックの作成
- 05inject() によるルートのテスト
活用シーン
- 01型安全な Fastify API の構築
- 02ルートの OpenAPI 仕様生成
- 03再利用可能なプラグインとリクエスト処理の作成
- 04ルートのブラックボックステスト
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ blockmatic/ basilic-skills --skill fastify-v5インストール後、Claude Code で/fastify-v5を入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/hooks.mdinstance-config.mdopenapi-integration.mdplugins.mdtesting.mdtemplates/hook-plugin.tsplugin.tsroute-schema.tstest-utils.ts詳細
スキル:fastify
対象範囲
- 対象:TypeBox スキーマ、型安全なルート定義、自動 OpenAPI 生成、プラグイン、フック、テストを使用する Fastify v5 以降
- 対象外:データベース連携(drizzle-orm を参照)
前提条件
- Fastify v5 以降
- TypeBox の型プロバイダーとして
@fastify/type-provider-typeboxを使用 - スキーマ定義に
@sinclair/typeboxを使用 - 厳格モードの TypeScript v5 以降
原則
- ルートのバリデーション(params、query、body、response)には TypeBox スキーマを使用します
- スキーマから型を自動推論するために
TypeBoxTypeProviderを使用します - すべてのステータスコードにレスポンススキーマを定義します
- スキーマから OpenAPI を生成します(
@fastify/swaggerを使用) - リクエストの型(
request.params、request.query、request.body)はスキーマから推論されます - レスポンスのバリデーションはスキーマに基づいて自動的に行われます
制約
必須
- 型安全性のために
TypeBoxTypeProviderを使用します:fastify.withTypeProvider<TypeBoxTypeProvider>() - すべてのステータスコードにレスポンススキーマを定義します
- スキーマ定義には TypeBox の
Type.*コンストラクターを使用します
推奨
- OpenAPI 生成のためにルートスキーマで
operationIdを使用します - OpenAPI ドキュメントでルートを整理するために
tagsを使用します - エラーケース用のエラーレスポンススキーマを定義します
避けること
- 手動の型アサーション(型はスキーマから推論されます)
- レスポンススキーマ定義の省略
- 同じルートでの TypeBox と他のスキーマライブラリの併用
連携
- データベース連携では drizzle-orm と組み合わせます
- openapi-ts のコード生成と互換性のある OpenAPI 仕様を生成します
パターン
ルートスキーマのパターン
import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync } from 'fastify'
const UserSchema = Type.Object({
id: Type.String(),
email: Type.String({ format: 'email' }),
name: Type.String(),
})
const userRoutes: FastifyPluginAsync = async fastify => {
fastify.get('/users/:id', {
schema: {
operationId: 'getUser',
params: Type.Object({ id: Type.String() }),
response: {
200: UserSchema,
404: Type.Object({ code: Type.String(), message: Type.String() }),
},
},
}, async (request, reply) => {
// request.params.id is typed
const { id } = request.params
return reply.send(user)
})
}
スキーマの型
Type.String()
Type.Number()
Type.Boolean()
Type.Object({ id: Type.String() })
Type.Array(Type.String())
Type.Optional(Type.String())
Type.Union([Type.String(), Type.Number()])
完全な例については、ルートスキーマのテンプレート を参照してください。
インスタンスの設定
TypeBox 型プロバイダー、ロガー、リクエスト設定を使用して Fastify インスタンスを設定します:
import type { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import Fastify, { LogController } from 'fastify'
const fastify = Fastify({
logger: {
level: 'info',
transport: process.env.NODE_ENV === 'development' ? {
target: 'pino-pretty',
} : undefined,
},
trustProxy: true,
bodyLimit: 1048576, // 1MB
requestTimeout: 30000,
requestIdHeader: 'x-request-id',
logController: new LogController({ requestIdLogLabel: 'reqId', disableRequestLogging: false }),
}).withTypeProvider<TypeBoxTypeProvider>()
完全なセットアップについては、インスタンス設定 を参照してください。
プラグインの開発
カプセル化されない動作を実現する再利用可能なプラグインを fastify-plugin で作成します:
import type { FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'
const myPlugin: FastifyPluginAsync = async fastify => {
// Plugin logic
}
export default fp(myPlugin, {
name: 'my-plugin',
})
例については、プラグインのパターン と プラグインのテンプレート を参照してください。
フック(リクエストのライフサイクル)
フックを使って、リクエストの割り込み、レスポンスの変更、エラーの処理を行います:
fastify.addHook('onRequest', async (request, reply) => {
// Add security headers, logging, etc.
})
fastify.addHook('onResponse', async (request, reply) => {
// Modify response, add headers, etc.
})
fastify.addHook('onError', async (request, reply, error) => {
// Handle errors
})
パターンについては、フックガイド と フックプラグインのテンプレート を参照してください。
inject() を使用したテスト
Fastify の inject() メソッドを使って、ブラックボックステストとしてルートをテストします:
const response = await fastify.inject({
method: 'GET',
url: '/users/123',
})
expect(response.statusCode).toBe(200)
const data = JSON.parse(response.body)
セットアップについては、テストのパターン と テストユーティリティのテンプレート を参照してください。
ストリーミングレスポンス
ストリーミングレスポンス(Server-Sent Events、テキストストリームなど)を処理します:
fastify.post('/stream', {
schema: {
response: {
200: Type.String({ description: 'Streaming response' }),
},
},
}, async (request, reply) => {
reply.header('Content-Type', 'text/event-stream')
reply.header('Cache-Control', 'no-cache')
return reply.send(stream)
})
よく使うプラグイン
レート制限
import rateLimit from '@fastify/rate-limit'
await fastify.register(rateLimit, {
max: 100,
timeWindow: 60000,
keyGenerator: request => request.ip,
})
CORS
import cors from '@fastify/cors'
await fastify.register(cors, {
origin: (origin, callback) => {
// Validate origin
callback(null, true)
},
credentials: false,
})
エラーハンドラー
fastify.setErrorHandler((error, request, reply) => {
// Global error handling
reply.status(error.statusCode ?? 500).send({
code: 'ERROR',
message: error.message,
})
})
グレースフルシャットダウン
プロセスシグナルを処理して、グレースフルシャットダウンを行います:
const shutdown = async (signal: string) => {
fastify.log.info({ signal }, 'Shutting down')
await fastify.close()
process.exit(0)
}
process.on('SIGTERM', () => shutdown('SIGTERM'))
process.on('SIGINT', () => shutdown('SIGINT'))
AutoLoad パターン
プラグインとルートを自動検出するために @fastify/autoload を使用します:
import AutoLoad from '@fastify/autoload'
await fastify.register(AutoLoad, {
dir: path.join(__dirname, 'plugins'),
forceESM: true,
})
参考資料
- OpenAPI 連携 - OpenAPI 生成のパターン
- プラグインのパターン - fastify-plugin を使ったプラグイン開発
- フックガイド - リクエストのライフサイクルフック
- テストのパターン - inject() を使ったテスト
- インスタンス設定 - Fastify インスタンスのセットアップ
コメント
Markdown 対応