mcpField
A
api-framework-nestjs

api-framework-nestjs

github.com/agents-inc開発2642 回インストール2 日前に更新
リポジトリ

api-framework-nestjs について

NestJS で Node.js バックエンドを構築する TypeScript 開発者向けのパターンガイドです。モジュール構成と依存性注入を軸に、ルーティング、DTO 検証、例外処理、リクエスト処理層の役割を解説します。

主な機能

  1. 01機能単位のモジュール構成
  2. 02コントローラーとサービスの分離
  3. 03DTO と宣言的なリクエスト検証
  4. 04依存性注入とカスタムプロバイダー
  5. 05ガード、インターセプター、パイプ、フィルター

活用シーン

  1. 01構造化された REST API の構築
  2. 02リクエストボディやパラメーターの検証規則の定義
  3. 03認証とロールベースのアクセス制御の実装
  4. 04ログ、レスポンス変換、例外処理の組み立て

インストール

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

$npx skills add https://github.com/agents-inc/skills --skill api-framework-nestjs

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

同梱ファイル

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

metadata.yaml
reference.md
examples/
advanced.md
auth.md
core.md
database.md
testing.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 層)、サービス(ビジネスロジック)、およびそれを支えるインフラストラクチャ(ガード、パイプ、インターセプター、フィルター)を含むモジュールとして構成されます。

基本原則:

  1. モジュール性 — 関連するコントローラー、サービス、プロバイダーを機能モジュールにまとめます。モジュールは主要な構成単位です。
  2. 依存性の注入 — サービスを手動でインスタンス化してはいけません。@Injectable() として宣言し、コンストラクターインジェクションを通じて NestJS に依存関係グラフを解決させます。
  3. デコレーター駆動 — デコレーター(@Controller、@Get、@Body、@UseGuards)は、NestJS がルーティング、バリデーション、ミドルウェアのパイプラインを構築するために使うメタデータを付与します。
  4. 関心の分離 — コントローラーは HTTP リクエストとレスポンスを処理します。サービスはビジネスロジックを処理します。ガードは認可を処理します。パイプはバリデーションと変換を処理します。フィルターは例外を処理します。
  5. 設定より規約 — 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>

コメント