fastify-typescript について
Fastify と TypeScript で型安全な API を構築するためのスキルです。ルート設計、検証、プラグイン、データアクセス、テスト、セキュリティの指針を扱います。
主な機能
- 01TypeScript の型付けと命名規則
- 02Fastify ルートのモジュール化
- 03TypeBox による JSON Schema 検証
- 04プラグインとデコレーターのパターン
- 05Prisma のデータアクセス指針
- 06テストとセキュリティの実践
活用シーン
- 01リソース別の Fastify API 構成
- 02型安全なリクエスト・レスポンス検証の追加
- 03プラグインを介した Prisma の統合
- 04ルートテストと API セキュリティの計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mindrally/ skills --skill fastify-typescriptインストール後、Claude Code で/fastify-typescriptを入力して読み込まれたか確認します。
詳細
Fastify と TypeScript の開発
高いパフォーマンスと型安全性を備えた API の構築に関する深い知識を持つ、Fastify と TypeScript 開発のエキスパートです。
TypeScript の一般的なガイドライン
基本原則
- すべてのコードとドキュメントには英語を使用します
- 変数と関数(引数と戻り値)には必ず型を宣言します
any型の使用は避け、必要な型を作成します- 公開クラスとメソッドのドキュメントには JSDoc を使用します
- 簡潔で保守しやすく、技術的に正確なコードを書きます
- 関数型および宣言型のプログラミングパターンを使用し、クラスは避けます
- DRY 原則に従い、反復とモジュール化を優先します
命名規則
- 型とインターフェースには PascalCase を使用します
- 変数、関数、メソッドには camelCase を使用します
- ファイル名とディレクトリ名には kebab-case を使用します
- 環境変数には UPPERCASE を使用します
isLoading、hasError、canDeleteのように、助動詞を使った説明的な変数名を使用します- 各関数の名前は動詞で始めます
関数
- 関数は単一の目的を持つ短いものにします
- 単純な処理にはアロー関数を使用します
- コードベース全体で一貫して async/await を使用します
- 複数の引数には RO-RO パターン(オブジェクトを受け取り、オブジェクトを返す)を使用します
型とインターフェース
- オブジェクトの形状には、型よりインターフェースを優先します
- enum は避け、代わりにマップまたは const オブジェクトを使用します
- 実行時の検証には Zod を使用し、型を推論します
- 不変プロパティには
readonlyを使用します - 型のみをインポートする場合は
import typeを使用します
Fastify 固有のガイドライン
プロジェクト構成
src/
routes/
{resource}/
index.ts
handlers.ts
schemas.ts
plugins/
auth.ts
database.ts
cors.ts
services/
{domain}Service.ts
repositories/
{entity}Repository.ts
types/
index.ts
utils/
config/
app.ts
server.ts
ルートの構成
- リソースまたはドメインごとにルートを整理します
- モジュール形式で登録するにはルートプラグインを使用します
- ルートハンドラーと並べてスキーマを定義します
- API のバージョン管理にはルートプレフィックスを使用します
import { FastifyPluginAsync } from 'fastify';
const usersRoutes: FastifyPluginAsync = async (fastify) => {
fastify.get('/', { schema: listUsersSchema }, listUsersHandler);
fastify.get('/:id', { schema: getUserSchema }, getUserHandler);
fastify.post('/', { schema: createUserSchema }, createUserHandler);
fastify.put('/:id', { schema: updateUserSchema }, updateUserHandler);
fastify.delete('/:id', { schema: deleteUserSchema }, deleteUserHandler);
};
export default usersRoutes;
JSON Schema / Ajv によるスキーマ検証
- すべてのリクエストとレスポンスの検証に JSON スキーマを定義します
- 型安全なスキーマ定義には @sinclair/typebox を使用します
- Fastify に組み込まれている Ajv 連携を活用します
import { Type, Static } from '@sinclair/typebox';
const UserSchema = Type.Object({
id: Type.String({ format: 'uuid' }),
name: Type.String({ minLength: 1 }),
email: Type.String({ format: 'email' }),
createdAt: Type.String({ format: 'date-time' }),
});
type User = Static<typeof UserSchema>;
const createUserSchema = {
body: Type.Object({
name: Type.String({ minLength: 1 }),
email: Type.String({ format: 'email' }),
}),
response: {
201: UserSchema,
400: ErrorSchema,
},
};
プラグインとデコレーター
- 共通機能にはプラグインを使用します
- Fastify インスタンスにサービスとユーティリティをデコレートします
- 適切なカプセル化を行ってプラグインを登録します
import fp from 'fastify-plugin';
const databasePlugin = fp(async (fastify) => {
const prisma = new PrismaClient();
await prisma.$connect();
fastify.decorate('prisma', prisma);
fastify.addHook('onClose', async () => {
await prisma.$disconnect();
});
});
export default databasePlugin;
Prisma との連携
- データベース操作には ORM として Prisma を使用します
- データアクセス用のリポジトリークラスを作成します
- 複雑な操作にはトランザクションを使用します
class UserRepository {
constructor(private prisma: PrismaClient) {}
async findById(id: string): Promise<User | null> {
return this.prisma.user.findUnique({ where: { id } });
}
async create(data: CreateUserInput): Promise<User> {
return this.prisma.user.create({ data });
}
}
エラー処理
- Fastify に組み込まれているエラー処理を使用します
- ドメインエラー用のカスタムエラークラスを作成します
- 一貫性のあるエラーレスポンスを返します
import { FastifyError } from 'fastify';
class NotFoundError extends Error implements FastifyError {
code = 'NOT_FOUND';
statusCode = 404;
constructor(resource: string, id: string) {
super(`${resource} with id ${id} not found`);
this.name = 'NotFoundError';
}
}
// Global error handler
fastify.setErrorHandler((error, request, reply) => {
const statusCode = error.statusCode || 500;
reply.status(statusCode).send({
error: error.name,
message: error.message,
statusCode,
});
});
Jest によるテスト
- サービスとハンドラーのユニットテストを作成します
- ルートには統合テストを使用します
- 外部依存関係をモックします
import { build } from '../app';
describe('Users API', () => {
let app: FastifyInstance;
beforeAll(async () => {
app = await build();
});
afterAll(async () => {
await app.close();
});
it('should list users', async () => {
const response = await app.inject({
method: 'GET',
url: '/api/users',
});
expect(response.statusCode).toBe(200);
expect(JSON.parse(response.payload)).toBeInstanceOf(Array);
});
});
パフォーマンス
- Fastify は Node.js フレームワークの中でも特に高速です
- スキーマ検証を使用して、シリアライズを自動的に最適化します
- 本番環境では必要な場合にのみロギングを有効にします
- データベース接続にはコネクションプーリングを使用します
セキュリティ
- セキュリティヘッダーには @fastify/helmet を使用します
- @fastify/rate-limit でレート制限を実装します
- CORS の設定には @fastify/cors を使用します
- JSON Schema ですべての入力を検証します
- @fastify/jwt を使用して JWT 認証を実装します
コメント
Markdown 対応