api-framework-nestjs について
NestJS で Node.js バックエンドを構築する TypeScript 開発者向けのパターンガイドです。モジュール構成と依存性注入を軸に、ルーティング、DTO 検証、例外処理、リクエスト処理層の役割を解説します。
主な機能
- 01機能単位のモジュール構成
- 02コントローラーとサービスの分離
- 03DTO と宣言的なリクエスト検証
- 04依存性注入とカスタムプロバイダー
- 05ガード、インターセプター、パイプ、フィルター
活用シーン
- 01構造化された REST API の構築
- 02リクエストボディやパラメーターの検証規則の定義
- 03認証とロールベースのアクセス制御の実装
- 04ログ、レスポンス変換、例外処理の組み立て
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-framework-nestjsインストール後、Claude Code で/api-framework-nestjsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/advanced.mdauth.mdcore.mddatabase.mdtesting.md詳細
NestJS のパターン
クイックガイド: NestJS は、TypeScript を基盤とする、独自の設計方針を持つモジュール型の Node.js フレームワークです。モジュールで機能を整理し、コントローラーで HTTP ルーティングを行い、依存性注入を用いてサービスにビジネスロジックを実装します。バリデーションには class-validator を使った DTO を、認証にはガードを、エラー処理には例外フィルターを使用します。重要な注意点:サービスは必ずモジュールの
providersに登録してください。whitelist: trueを指定してValidationPipeを必ずグローバルに有効にしてください。ビジネスロジックをコントローラーに記述せず、サービスをnewでインスタンス化しないでください。NestJS 11 は現在の安定版です(オプトイン方式の SWC コンパイラー、Express v5、終了フックの順序変更)。
<critical_requirements>
重要:このスキルを使用する前に
(すべてのサービスで必ず @Injectable() を使用し、モジュールの providers 配列に登録してください)
(whitelist: true と forbidNonWhitelisted: true を指定して ValidationPipe を必ずグローバルに有効にしてください)
(すべてのリクエストボディのバリデーションには、class-validator のデコレーターを使った DTO を必ず使用してください。コントローラーで手動のバリデーションを行わないでください)
(必ず NestJS 組み込みの HTTP 例外(NotFoundException、BadRequestException など)をスローしてください。生のステータスコードを送信しないでください)
(依存関係には必ずコンストラクターインジェクションを使用してください。サービスを new で手動でインスタンス化しないでください)
</critical_requirements>
自動検出: NestJS、@nestjs/common、@nestjs/core、@Module、@Controller、@Injectable、@Get、@Post、@Body、@Param、@Query、@UseGuards、@UseInterceptors、@UsePipes、@UseFilters、CanActivate、NestInterceptor、PipeTransform、ExceptionFilter、ValidationPipe、class-validator、class-transformer
使用する場面:
- TypeScript と依存性注入を使って、構造化されたバックエンド API を構築する場合
- 明確な関心の分離を備えたモジュール型アーキテクチャが必要なアプリケーション
- 宣言的なバリデーション、認証、ロールベースのアクセス制御を備えた REST API
- ガード/インターセプター/パイプ/フィルターによるリクエストライフサイクルが必要なプロジェクト
使用しない場面:
- フレームワークを必要としない単純なスクリプトやサーバーレス関数
- Express/Fastify だけで十分なプロジェクト(DI やモジュールが不要な場合)
- フロントエンドのコード
詳細なリソース:
- examples/core.md — 機能モジュール、CRUD、DTO、動的モジュール、例外フィルター、カスタムプロバイダー
- examples/database.md — データベース統合やトランザクションのための NestJS の DI パターン
- examples/auth.md — Passport.js の統合、JWT 戦略、認証ガード、RBAC
- examples/testing.md —
Test.createTestingModuleを使った単体テスト、supertest を使った E2E テスト - examples/advanced.md — インターセプター、カスタムパイプ、カスタムデコレーター、設定、CQRS、Swagger
- reference.md — CLI コマンド、プロジェクト構成、デコレーターの一覧、判断フレームワーク
## 設計思想
NestJS は、Angular に着想を得たモジュール式のデコレーター駆動アーキテクチャを採用しています。各機能は、コントローラー(HTTP 層)、サービス(ビジネスロジック)、およびそれを支えるインフラストラクチャ(ガード、パイプ、インターセプター、フィルター)を含むモジュールとして構成されます。
基本原則:
- モジュール性 — 関連するコントローラー、サービス、プロバイダーを機能モジュールにまとめます。モジュールは主要な構成単位です。
- 依存性の注入 — サービスを手動でインスタンス化してはいけません。
@Injectable()として宣言し、コンストラクターインジェクションを通じて NestJS に依存関係グラフを解決させます。 - デコレーター駆動 — デコレーター(
@Controller、@Get、@Body、@UseGuards)は、NestJS がルーティング、バリデーション、ミドルウェアのパイプラインを構築するために使うメタデータを付与します。 - 関心の分離 — コントローラーは HTTP リクエストとレスポンスを処理します。サービスはビジネスロジックを処理します。ガードは認可を処理します。パイプはバリデーションと変換を処理します。フィルターは例外を処理します。
- 設定より規約 — NestJS の規約(機能ごとに 1 つのモジュール、リソースごとに 1 つのコントローラー、バリデーション用の DTO)に従うことで、必要な機能があらかじめ揃った構成を利用できます。
主要なパターン
モジュールシステム
すべての NestJS アプリには、機能モジュールをインポートするルート AppModule があります。各機能モジュールには、その機能のコントローラー、サービス、プロバイダーをまとめます。他のモジュールで必要となるサービスはエクスポートします。
// Feature module — one per resource
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Available to other modules
})
export class UsersModule {}
優れている理由: 機能ごとにカプセル化でき、インポート/エクスポートによって依存関係グラフが明確になり、単独でテストできます。
CRUD モジュール、動的モジュール、カスタムプロバイダーの完全な例については、examples/core.md を参照してください。
コントローラー — 薄いルーティング層
コントローラーはリクエストデータの抽出とサービスへの委譲だけを行うべきです。ビジネスロジックは含めません。
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get(":id")
findOne(@Param("id", ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
}
優れている理由: ParseIntPipe がパラメーターを検証して変換し、明示的なステータスには @HttpCode を使い、サービスに処理を委譲するためコントローラーを薄く保てます。
アンチパターン: コントローラーでビジネスロジック、手動のバリデーション、データベースアクセスを行うこと。必ずサービスに委譲してください。
class-validator を使った DTO
すべてのリクエストバリデーションには、class-validator デコレーターを使った DTO を使用します。ValidationPipe をグローバルに有効にします。
const MIN_PASSWORD_LENGTH = 8;
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(MIN_PASSWORD_LENGTH)
password: string;
}
// Update DTO — reuses validation rules
export class UpdateUserDto extends PartialType(CreateUserDto) {}
// main.ts — Enable globally
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // Strip unknown properties
forbidNonWhitelisted: true, // Reject unknown properties
transform: true, // Auto-transform to DTO instances
}),
);
優れている理由: 宣言的にバリデーションを定義でき、whitelist によって一括代入を防止し、PartialType によってルールの重複を避けられます。
ネストされた DTO、ページネーション用のクエリー DTO、バリデーショングループの例については、examples/core.md を参照してください。
サービスと依存性の注入
サービスにはビジネスロジックを記述します。@Injectable() を付与し、コンストラクター経由で注入します。
@Injectable()
export class UsersService {
findOne(id: number): User {
const user = this.users.find((u) => u.id === id);
if (!user) {
throw new NotFoundException(`User with id ${id} not found`);
}
return user;
}
}
優れている理由: @Injectable() によって DI が有効になり、NestJS の HTTP 例外をスローでき、HTTP に関する懸念を含まない純粋なビジネスロジックを実現できます。
カスタムプロバイダー
クラス以外のプロバイダー(ファクトリー、値、クラスのプロバイダー)には、トークンベースのインジェクションを使用します。
const DATABASE_CONNECTION = "DATABASE_CONNECTION";
const databaseProvider = {
provide: DATABASE_CONNECTION,
useFactory: async (configService: ConfigService) => {
return createConnection(configService.get("database"));
},
inject: [ConfigService],
};
// Inject with @Inject token
constructor(@Inject(DATABASE_CONNECTION) private readonly db: Connection) {}
プロバイダーの完全な例については、examples/core.md を参照してください。
例外処理
サービスから NestJS 組み込みの HTTP 例外をスローします。カスタムのエラーレスポンス形式には、例外フィルターを使用します。
// Service — throw built-in exceptions
throw new NotFoundException("Resource not found");
throw new ConflictException("Resource already exists");
throw new BadRequestException("Invalid input");
throw new UnauthorizedException("Authentication required");
重要な点: NestJS はこれらを正しいステータスコードを持つ適切な HTTP レスポンスに自動変換します。生のステータスコードを送信してはいけません。
カスタムのエラーレスポンス形式には、グローバルな @Catch() 例外フィルターを使用します。examples/core.md を参照してください。
ガードとミドルウェア
ガードはリクエストを続行するかどうか(認可)を判断します。ミドルウェアはルーティング前に実行されます(ロギング、CORS)。
// Guard — implements CanActivate
@Injectable()
export class JwtAuthGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>();
// Validate token, attach user to request
return true;
}
}
// Apply to routes
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller("admin")
export class AdminController {}
優れている理由: ガードは注入可能(サービスを使用可能)で、組み合わせ可能(順番に実行)です。また、Reflector を使ってメタデータに基づくアクセス制御を実現できます。
JWT 認証、Passport.js との統合、RBAC、@Public() デコレーターの例については、examples/auth.md を参照してください。
インターセプター
インターセプターは、横断的関心事(レスポンスのラップ、ロギング、キャッシュ)に対応するため、ハンドラーの実行をラップします。
@Injectable()
export class TransformResponseInterceptor<T> implements NestInterceptor {
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<ApiResponse<T>> {
return next.handle().pipe(
map((data) => ({
success: true,
data,
timestamp: new Date().toISOString(),
})),
);
}
}
ロギング、キャッシュ、カスタムパイプのパターンについては、examples/advanced.md を参照してください。
<decision_framework>
判断の指針
リクエストのライフサイクル
Incoming Request
→ Middleware (logging, CORS, body parsing)
→ Guards (authentication, authorization)
→ Interceptors (pre-handler: transform request, start timing)
→ Pipes (validation, transformation)
→ Route Handler (controller method)
→ Interceptors (post-handler: transform response, log timing)
→ Exception Filters (catch and format errors)
→ Response
</decision_framework>
使用するレイヤー
Need to process raw request before routing?
├─ YES → Middleware (logging, CORS, rate limiting)
└─ NO → Does it decide allow/deny for a route?
├─ YES → Guard (auth, roles, permissions)
└─ NO → Does it transform/validate input data?
├─ YES → Pipe (validation, type coercion)
└─ NO → Does it wrap handler execution?
├─ YES → Interceptor (timing, caching, response mapping)
└─ NO → Does it handle errors?
├─ YES → Exception Filter
└─ NO → Put it in the service layer
モジュール構成
Is this a cross-cutting concern (auth, config, logging)?
├─ YES → Global module or shared module
└─ NO → Is it a business feature (users, orders, products)?
├─ YES → Feature module (users.module.ts)
└─ NO → Is it infrastructure (database, cache, queue)?
├─ YES → Infrastructure module
└─ NO → Part of the closest feature module
</decision_framework>
<red_flags>
危険な兆候
優先度の高い問題:
- コントローラーにビジネスロジックを記述し、サービスに記述していない
- サービスに
@Injectable()がない(実行時に DI が暗黙に失敗します) ValidationPipeをグローバルに有効にしていない(DTO が検証されません)- 型付き DTO の代わりに、リクエストボディに
anyを使用している - コンストラクターインジェクションの代わりに、
newでサービスをインスタンス化している - NestJS の HTTP 例外ではなく生の
Errorをスローしている(適切なステータスではなく 500 が返されます)
優先度が中程度の問題:
- モジュールからサービスをエクスポートしていない(他のモジュールからインポートできません)
- 1 つのサービスだけが必要なのに、モジュール全体をインポートしている
- ValidationPipe に
whitelist: trueがない(一括代入の脆弱性につながります) - ストリーミング以外の用途で
@Res()デコレーターを使用している(NestJS のレスポンス処理を無効にします) - 更新用 DTO に
PartialType/PickType/OmitTypeを使用していない(検証が重複します)
よくある間違い:
- モジュール間の循環依存 —
forwardRef()を使うか、共有ロジックを切り出して再構成してください - モジュールへのプロバイダー登録を忘れている — サービスのインジェクションが実行時に失敗します
- 非同期処理に同期ガードを使用している —
Promise<boolean>またはObservable<boolean>を返してください - カスタムフィルターで一部の例外タイプを処理していない — 不明なエラーをすべて捕捉できる処理を必ず用意してください
注意点とエッジケース:
@UseGuards(AuthGuard)にはインスタンスではなくクラス参照を渡します — NestJS が DI を通じてインスタンス化しますtransform: trueを指定したValidationPipeは、クエリパラメーターを宣言された型に自動変換します- ガードはミドルウェアの後、インターセプターとパイプの前に実行されます
- 引数なしの
@Catch()はHttpExceptionだけでなく、すべての例外を捕捉します IntrinsicException(NestJS 11)はフレームワークによる自動ログ記録なしでスローされます — 想定内のフロー制御に便利です- NestJS 11:終了時のライフサイクルフック(
OnModuleDestroy、OnApplicationShutdown)が逆順で実行されるようになりました - NestJS 11:Express v5 では名前付きワイルドカード(
/*ではなく/*splat)が必要です - NestJS 11:SWC は
nest-cli.json("builder": "swc")でオプトインして使用できるコンパイラーです — ビルドは tsc より 20 倍高速です - NestJS 11:
ParseDatePipeが組み込みになりました — カスタムの日付解析パイプは不要です - リクエストスコープのプロバイダー(
Scope.REQUEST)はパフォーマンスに影響します — 必要な場合にのみ使用してください forwardRef()は最後の手段にしてください — 循環依存は通常、設計上の問題を示しています
</red_flags>
<critical_reminders>
重要な注意事項
(すべてのサービスで @Injectable() を使用し、モジュールの providers 配列に登録する必要があります)
(ValidationPipe を whitelist: true および forbidNonWhitelisted: true とともにグローバルに有効にする必要があります)
(すべてのリクエストボディの検証に、class-validator デコレーターを使用した DTO を使う必要があります — コントローラー内で手動検証してはいけません)
(NestJS 組み込みの HTTP 例外(NotFoundException、BadRequestException など)をスローする必要があります — 生のステータスコードを返してはいけません)
(依存関係にはコンストラクターインジェクションを使用する必要があります — new でサービスを手動でインスタンス化してはいけません)
これらのルールに従わないと、検証されず、テストできず、依存性注入が壊れた NestJS コードになります。
</critical_reminders>