fastify について
TypeScript 開発者向けの Fastify による Node.js バックエンド構築ガイドです。スキーマ検証、カプセル化されたプラグイン、エラー処理、セキュリティ、正常終了、インメモリでのルートテストを扱います。
主な機能
- 01スキーマによるリクエストとレスポンスの検証
- 02カプセル化されたプラグインでルートを整理
- 03エラー処理の一元化
- 04セキュリティプラグインとペイロード制限
- 05プロセスシグナルに応じた正常終了
- 06インメモリインジェクションでルートをテスト
活用シーン
- 01型付き Node.js HTTP API の構築
- 02ルートと依存関係の分離
- 03ハンドラーから一貫したエラーを返す
- 04ポートを開かずにエンドポイントをテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bobmatnyc/ claude-mpm-skills --skill fastifyインストール後、Claude Code で/fastifyを入力して読み込まれたか確認します。
同梱ファイルmetadata.json
詳細
Fastify(TypeScript) - 本番環境向けバックエンドフレームワーク
概要
Fastify は、JSON スキーマによるバリデーション、カプセル化されたプラグイン、優れた開発者体験を中心に構築された、高性能な Node.js ウェブフレームワークです。TypeScript では、型プロバイダー(Zod または TypeBox)と Fastify を組み合わせることで、実行時のバリデーションと静的型を一致させられます。
クイックスタート
最小限のサーバー
✅ 正しい例:型付きレスポンスを返す基本的なサーバー
import Fastify from "fastify";
const app = Fastify({ logger: true });
app.get("/health", async () => ({ status: "ok" as const }));
await app.listen({ host: "0.0.0.0", port: 3000 });
❌ 誤った例:listen の完了を待たずにサーバーを起動する
app.listen({ port: 3000 });
console.log("started"); // races startup and hides bind failures
スキーマバリデーションと型プロバイダー
Fastify は JSON スキーマを使ってリクエストとレスポンスを検証します。型の重複を避けるには、型プロバイダーを使用します。
Zod プロバイダー(フルスタック TypeScript におすすめ)
✅ 正しい例:Zod スキーマでバリデーションと型を定義する
import Fastify from "fastify";
import { z } from "zod";
import { ZodTypeProvider } from "fastify-type-provider-zod";
const app = Fastify({ logger: true }).withTypeProvider<ZodTypeProvider>();
const Query = z.object({ q: z.string().min(1) });
app.get(
"/search",
{ schema: { querystring: Query } },
async (req) => {
return { q: req.query.q };
},
);
await app.listen({ port: 3000 });
TypeBox プロバイダー(OpenAPI とパフォーマンスにおすすめ)
✅ 正しい例:TypeBox スキーマ
import Fastify from "fastify";
import { Type } from "@sinclair/typebox";
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox";
const app = Fastify({ logger: true }).withTypeProvider<TypeBoxTypeProvider>();
const Params = Type.Object({ id: Type.String({ minLength: 1 }) });
const Reply = Type.Object({ id: Type.String() });
app.get(
"/users/:id",
{ schema: { params: Params, response: { 200: Reply } } },
async (req) => ({ id: req.params.id }),
);
await app.listen({ port: 3000 });
プラグインアーキテクチャ(カプセル化)
プラグインを使い、関心事(認証、データベース、ルート)を分離して、テストしやすくします。
✅ 正しい例:ルートプラグイン
import type { FastifyPluginAsync } from "fastify";
export const usersRoutes: FastifyPluginAsync = async (app) => {
app.get("/", async () => [{ id: "1" }]);
app.get("/:id", async (req) => ({ id: (req.params as any).id }));
};
✅ 正しい例:プレフィックスを指定して登録する
app.register(usersRoutes, { prefix: "/api/v1/users" });
エラーハンドリング
予期しないエラーを一元管理し、安定した形式のエラーを返します。
✅ 正しい例:setErrorHandler
app.setErrorHandler((err, req, reply) => {
req.log.error({ err }, "request failed");
reply.status(500).send({ error: "internal" as const });
});
セキュリティ強化(基本)
標準的なセキュリティプラグインを追加し、ペイロードのサイズ制限を適用します。
✅ 正しい例:Helmet、CORS、レート制限
import helmet from "@fastify/helmet";
import cors from "@fastify/cors";
import rateLimit from "@fastify/rate-limit";
await app.register(helmet);
await app.register(cors, { origin: false });
await app.register(rateLimit, { max: 100, timeWindow: "1 minute" });
グレースフルシャットダウン
SIGINT/SIGTERM の受信時に、HTTP サーバーと下流のクライアント(DB、キュー)を終了します。
✅ 正しい例:シグナル受信時に終了する
const close = async (signal: string) => {
app.log.info({ signal }, "shutting down");
await app.close();
process.exit(0);
};
process.on("SIGINT", () => void close("SIGINT"));
process.on("SIGTERM", () => void close("SIGTERM"));
テスト(Fastify inject)
ポートをバインドせずに、メモリ上でルートをテストします。
✅ 正しい例:リクエストを inject する
import Fastify from "fastify";
import { describe, it, expect } from "vitest";
describe("health", () => {
it("returns ok", async () => {
const app = Fastify();
app.get("/health", async () => ({ status: "ok" as const }));
const res = await app.inject({ method: "GET", url: "/health" });
expect(res.statusCode).toBe(200);
expect(res.json()).toEqual({ status: "ok" });
});
});
判断基準
Fastify と Express の比較
- スキーマベースのバリデーション、予測可能なプラグイン、高いスループットを重視する場合は、Fastify をおすすめします。
- 最小限のミドルウェアと、幅広く親しまれているエコシステムを重視する場合は、Express をおすすめします。
Zod と TypeBox の比較
- フォーム、tRPC、共有型など、すでに Zod を標準としているアプリケーションのコードベースには、Zod をおすすめします。
- OpenAPI の生成や、パフォーマンスが重要なバリデーションには、TypeBox をおすすめします。
アンチパターン
- リクエストのバリデーションを省略する。境界でスキーマを使って検証します。
- すべてを
main.tsに登録する。ルートと依存関係をプラグインに分離します。 - 生のエラーオブジェクトを返す。安定した形式のエラーを返し、詳細はログに記録します。
リソース
- Fastify: https://www.fastify.io/
- fastify-type-provider-zod: https://github.com/turkerdev/fastify-type-provider-zod
- @fastify/type-provider-typebox: https://github.com/fastify/fastify-type-provider-typebox