mcpField
F
fastify-v5

fastify-v5

github.com/blockmatic開発1221 回インストール5 週間前に更新
リポジトリ

fastify-v5 について

Fastify v5 と TypeScript を使う開発者向けの実践ガイドです。TypeBox による型安全なルート、OpenAPI 生成、プラグイン、フック、inject() によるテストを扱います。

主な機能

  1. 01TypeBox でリクエストとレスポンスのスキーマを定義
  2. 02スキーマからルート型を推論
  3. 03スキーマから OpenAPI を生成
  4. 04プラグインとリクエストフックの作成
  5. 05inject() によるルートのテスト

活用シーン

  1. 01型安全な Fastify API の構築
  2. 02ルートの OpenAPI 仕様生成
  3. 03再利用可能なプラグインとリクエスト処理の作成
  4. 04ルートのブラックボックステスト

インストール

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

$npx skills add https://github.com/blockmatic/basilic-skills --skill fastify-v5

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
hooks.md
instance-config.md
openapi-integration.md
plugins.md
testing.md
templates/
hook-plugin.ts
plugin.ts
route-schema.ts
test-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,
})

参考資料

コメント