nestjs-patterns
NestJSのアーキテクチャパターンに関するスキルで、モジュール・コントローラー・プロバイダー・DTOバリデーション・ガード・インターセプター・設定など、本番レベルのTypeScriptバックエンド構築に必要な要素を網羅します。NestJSプロジェクトの設計や実装時に活用できます。
description の原文を見る
NestJS 架构模式,涵盖模块、控制器、提供者、DTO 验证、守卫、拦截器、配置以及生产级 TypeScript 后端。
SKILL.md 本文
NestJS 開発パターン
モジュール化された TypeScript バックエンド向けの本番級 NestJS パターン。
使用すべき場面
- NestJS API またはサービスを構築する場合
- モジュール、コントローラー、プロバイダーを組織する場合
- DTO 検証、ガード、インターセプター、例外フィルターを追加する場合
- 環境対応設定とデータベース統合を構成する場合
- NestJS ユニットテストまたは HTTP エンドポイントをテストする場合
プロジェクト構造
src/
├── app.module.ts
├── main.ts
├── common/
│ ├── filters/
│ ├── guards/
│ ├── interceptors/
│ └── pipes/
├── config/
│ ├── configuration.ts
│ └── validation.ts
├── modules/
│ ├── auth/
│ │ ├── auth.controller.ts
│ │ ├── auth.module.ts
│ │ ├── auth.service.ts
│ │ ├── dto/
│ │ ├── guards/
│ │ └── strategies/
│ └── users/
│ ├── dto/
│ ├── entities/
│ ├── users.controller.ts
│ ├── users.module.ts
│ └── users.service.ts
└── prisma/ or database/
- ドメインコードは機能モジュール内に保つ。
- フィルター、デコレーター、ガード、インターセプターなどの横断的な関心事は
common/に配置する。 - DTO は所属するモジュールの近くに保つ。
ブートストラップとグローバル検証
async function bootstrap() {
const app = await NestFactory.create(AppModule, { bufferLogs: true });
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: { enableImplicitConversion: true },
}),
);
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
- 公開 API では常に
whitelistとforbidNonWhitelistedを有効にする。 - ルートごとに検証設定を繰り返すのではなく、単一のグローバル検証パイプを優先する。
モジュール、コントローラー、プロバイダー
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get(':id')
getById(@Param('id', ParseUUIDPipe) id: string) {
return this.usersService.getById(id);
}
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
}
@Injectable()
export class UsersService {
constructor(private readonly usersRepo: UsersRepository) {}
async create(dto: CreateUserDto) {
return this.usersRepo.create(dto);
}
}
- コントローラーはシンプルに保つ: HTTP 入力を解析し、プロバイダーを呼び出し、レスポンス DTO を返す。
- ビジネスロジックはコントローラーではなく、注入可能なサービスに配置する。
- 他のモジュールが本当に必要とするプロバイダーのみをエクスポートする。
DTO と検証
export class CreateUserDto {
@IsEmail()
email!: string;
@IsString()
@Length(2, 80)
name!: string;
@IsOptional()
@IsEnum(UserRole)
role?: UserRole;
}
- 各リクエスト DTO を
class-validatorで検証する。 - ORM エンティティを直接返すのではなく、専用のレスポンス DTO またはシリアライザーを使用する。
- パスワードハッシュ、トークン、監査列など、内部フィールドの漏洩を避ける。
認証、ガード、リクエストコンテキスト
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Get('admin/report')
getAdminReport(@Req() req: AuthenticatedRequest) {
return this.reportService.getForUser(req.user.id);
}
- 認証戦略とガードはモジュールローカルに保つ。本当に共有される場合を除く。
- ガード内に粗粒度のアクセスルールをコード化し、サービス内でリソース固有の認可を実施する。
- 認証済みリクエストオブジェクトには、明示的なリクエスト型を優先する。
例外フィルターとエラー形式
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
const request = host.switchToHttp().getRequest<Request>();
if (exception instanceof HttpException) {
return response.status(exception.getStatus()).json({
path: request.url,
error: exception.getResponse(),
});
}
return response.status(500).json({
path: request.url,
error: 'Internal server error',
});
}
}
- API 全体で一貫したエラーラッピング形式を維持する。
- 予期されたクライアントエラーはフレームワーク例外をスロー。予期しない失敗は集中的にログし、ラップする。
設定と環境検証
ConfigModule.forRoot({
isGlobal: true,
load: [configuration],
validate: validateEnv,
});
- 初回リクエスト時に遅延検証するのではなく、起動時に環境変数を検証する。
- 設定アクセスを型付きヘルパー関数または設定サービスの背後に制限する。
- 機能コード内の分岐ではなく、設定ファクトリー内で開発/ステージング/本番の関心事を分離する。
永続化とトランザクション
- リポジトリ/ORM コードはプロバイダーの背後に保つ。プロバイダーはドメイン言語で通信する。
- Prisma または TypeORM の場合、トランザクションワークフローをワークユニットを所有するサービス内に分離する。
- コントローラーから複数ステップの書き込み操作を直接調整させない。
テスト
describe('UsersController', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [UsersModule],
}).compile();
app = moduleRef.createNestApplication();
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
await app.init();
});
});
- モック依存項目でプロバイダーをユニットテストする。
- ガード、検証パイプ、例外フィルターにはリクエストレベルテストを追加する。
- テストで本番環境と同じグローバルパイプ/フィルターを再利用する。
本番デフォルト設定
- 構造化ログと関連付け ID をリクエストに対して有効にする。
- 環境/設定が無効な場合は、部分的な起動ではなく終了する。
- 明示的なヘルスチェック付きで、非同期プロバイダー初期化によりデータベース/キャッシュクライアントを優先する。
- バックグラウンドタスクとイベントコンシューマーを HTTP コントローラー内ではなく、独自のモジュール内に配置する。
- 公開エンドポイントではレート制限、認証、監査ログを明示的に有効にする。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- affaan-m
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/affaan-m/everything-claude-code / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。