Skip to main content

nestjs-expert

NestJS development principles and decision-making. Modern Node.js enterprise framework with TypeScript, dependency injection, modules.

ソース情報

リポジトリ
skeletorflet/opencode-kit
ソースの最終更新活動
2026年3月31日 19:12
検出された SKILL.md の言語
英語
スター
9
フォーク
1

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
nestjs-expert
description
NestJS development principles and decision-making. Modern Node.js enterprise framework with TypeScript, dependency injection, modules.
# NestJS Expert - Modern Node.js Enterprise Framework > NestJS development principles and decision-making. > **Learn to THINK, not copy-paste patterns.** --- ## ⚠️ How to Use This Skill This skill teaches **decision-making principles** for NestJS development. - ASK user for use case (API, Microservice, WebSocket, GraphQL) - Choose proper module structure for the project size - Use TypeScript properly with interfaces and DTOs --- ## 1. NestJS Core Concepts ### Architecture Overview ``` NestJS follows Angular-like architecture: ├── Modules (logical grouping) ├── Controllers (route handlers) ├── Services (business logic) ├── Providers (DI beans) ├── Pipes (validation) ├── Guards (auth) ├── Interceptors (middleware) └── Filters (error handling) ``` ### Directory Structure by Scale ``` Small (的单模块): src/ ├── app.controller.ts ├── app.service.ts ├── app.module.ts └── main.ts Medium (分模块): src/ ├── modules/ │ ├── users/ │ │ ├── users.controller.ts │ │ ├── users.service.ts │ │ ├── users.module.ts │ │ ├── dto/ │ │ └── entities/ │ └── auth/ ├── common/ │ ├── decorators/ │ ├── filters/ │ ├── guards/ │ └── interceptors/ └── config/ Large (DDD): src/ ├── domain/ │ ├── users/ │ │ ├── entities/ │ │ ├── repositories/ │ │ └── services/ │ └── orders/ ├── application/ │ ├── use-cases/ │ └── dtos/ ├── infrastructure/ │ ├── database/ │ └── external/ └── presentation/ ├── controllers/ └── modules/ ``` --- ## 2. Module System ### Feature Modules ```typescript // users/users.module.ts @Module({ imports: [ TypeOrmModule.forFeature([UserEntity]), // Entities managed by this module PassportModule.register({ defaultStrategy: 'jwt' }), forwardRef(() => AuthModule), // If there's circular dependency ], controllers: [UsersController], providers: [ UsersService, { provide: 'USER_REPOSITORY', useFactory: (dataSource: DataSource) => dataSource.getRepository(UserEntity), inject: ['DATA_SOURCE'], }, ], exports: [UsersService], // Make available to other modules }) export class UsersModule {} ``` ### Shared Modules ```typescript // common/common.module.ts @Global() @Module({ providers: [ { provide: 'LOGGER', useClass: Logger, }, ], exports: ['LOGGER'], }) export class CommonModule {} // Now use in any module by importing CommonModule ``` --- ## 3. Dependency Injection Patterns ### Constructor Injection ```typescript // Standard injection @Injectable() export class UsersService { constructor( private readonly usersRepository: UsersRepository, private readonly emailService: EmailService, @Inject('CONFIG') private config: ConfigService, ) {} } ``` ### Multiple Implementations ```typescript // Use interface export interface PaymentGateway { process(amount: number): Promise<PaymentResult>; } // Stripe implementation @Injectable() export class StripePaymentGateway implements PaymentGateway { async process(amount: number): Promise<PaymentResult> { // Stripe logic } } // PayPal implementation @Injectable() export class PayPalPaymentGateway implements PaymentGateway { async process(amount: number): Promise<PaymentResult> { // PayPal logic } } // Use with @Inject @Injectable() export class OrderService { constructor( @Inject('PaymentGateway') private paymentGateway: PaymentGateway, ) {} } // Register in module { provide: 'PaymentGateway', useClass: config.paymentProvider === 'stripe' ? StripePaymentGateway : PayPalPaymentGateway, } ``` ### Custom Providers ```typescript // Value provider { provide: 'APP_NAME', useValue: 'MyApp', } // Class provider (singleton) { provide: UsersService, useClass: UsersServiceImpl, } // Factory provider (complex instantiation) { provide: 'ANALYTICS', useFactory: (config: ConfigService) => { return new Analytics(config.analyticsKey); }, inject: [ConfigService], } ``` --- ## 4. Controllers and Routing ### REST Controller ```typescript @Controller('users') @UseGuards(JwtAuthGuard) @Serialize(UserDto) export class UsersController { constructor(private readonly usersService: UsersService) {} @Get() @HttpCode(200) async findAll(@Query() query: PaginationQuery) { return this.usersService.findAll(query.page, query.limit); } @Get(':id') @HttpCode(200) async findOne(@Param('id', ParseIntPipe) id: number) { return this.usersService.findOne(id); } @Post() @HttpCode(201) @UsePipes(new ValidationPipe({ transform: true })) async create(@Body() createUserDto: CreateUserDto) { return this.usersService.create(createUserDto); } @Patch(':id') @HttpCode(200) async update( @Param('id', ParseIntPipe) id: number, @Body() updateUserDto: UpdateUserDto, ) { return this.usersService.update(id, updateUserDto); } @Delete(':id') @HttpCode(204) async remove(@Param('id', ParseIntPipe) id: number) { return this.usersService.remove(id); } } ``` ### GraphQL Controller ```typescript @Resolver(() => User) export class UsersResolver { constructor(private readonly usersService: UsersService) {} @Query(() => [User]) async users(): Promise<User[]> { return this.usersService.findAll(); } @Mutation(() => User) @UseGuards(GqlJwtAuthGuard) async createUser(@Args('createUserInput') createUserInput: CreateUserInput): Promise<User> { return this.usersService.create(createUserInput); } @ResolveField() async posts(@Parent() user: User): Promise<Post[]> { return this.usersService.getUserPosts(user.id); } } ``` ### WebSocket Gateway ```typescript @WebSocketGateway({ namespace: 'chat', cors: { origin: '*' }, }) export class ChatGateway { @WebSocketServer() server: Server; afterInit(server: Server) { console.log('WebSocket Gateway initialized'); } @SubscribeMessage('message') handleMessage(client: Socket, payload: any): void { const message = { ...payload, timestamp: new Date() }; this.server.emit('message', message); } handleDisconnect(client: Socket) { console.log(`Client disconnected: ${client.id}`); } handleConnection(client: Socket) { console.log(`Client connected: ${client.id}`); } } ``` --- ## 5. Validation and Pipes ### Built-in ValidationPipe ```typescript // DTOs with class-validator export class CreateUserDto { @IsEmail() @IsNotEmpty() email: string; @IsString() @MinLength(8) @MaxLength(100) password: string; @IsOptional() @IsString() name?: string; @IsEnum(['user', 'admin', 'moderator']) role: UserRole; } // Global validation in main.ts async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes( new ValidationPipe({ whitelist: true, // Strip properties not in DTO forbidNonWhitelisted: true, // Throw error if extra properties transform: true, // Transform payloads to DTO instances transformOptions: { enableImplicitConversion: true }, }), ); await app.listen(3000); } ``` ### Custom Pipe ```typescript @Injectable() export class ParseIntPipe implements PipeTransform<string, number> { transform(value: string, metadata: ArgumentMetadata): number { const parsedValue = parseInt(value, 10); if (isNaN(parsedValue)) { throw new BadRequestException(`Invalid number: ${value}`); } return parsedValue; } } // Usage in controller @Get(':id') async findOne(@Param('id', ParseIntPipe) id: number) { return this.usersService.findOne(id); } ``` --- ## 6. Authentication ### JWT Auth with Guards ```typescript // jwt.strategy.ts @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: process.env.JWT_SECRET, }); } async validate(payload: JwtPayload) { const user = await this.usersService.findOne(payload.sub); if (!user) { throw new UnauthorizedException(); } return { userId: payload.sub, email: payload.email, roles: payload.roles }; } } // jwt-auth.guard.ts @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { canActivate(context: ExecutionContext) { return super.canActivate(context); } } // Usage in controller @UseGuards(JwtAuthGuard) @Get('profile') getProfile(@Request() req) { return req.user; } ``` ### Role-based Access Control ```typescript // Roles guard @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [ context.getHandler(), context.getClass(), ]); if (!requiredRoles) { return true; } const { user } = context.switchToHttp().getRequest(); return requiredRoles.some((role) => user.roles?.includes(role)); } } // Usage @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') @Delete(':id') async remove(@Param('id') id: string) { // Only admins can delete } ``` --- ## 7. Database Integration ### TypeORM Integration ```typescript // app.module.ts @Module({ imports: [ TypeOrmModule.forRoot({ type: 'postgres', host: 'localhost', port: 5432, username: 'postgres', password: 'password', database: 'mydb', entities: [User, Post], synchronize: false, // Don't use in production! logging: process.env.NODE_ENV === 'development', }), ], }) export class AppModule {} // Entity @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column({ unique: true }) email: string; @Column() @Transform(({ value }) => bcrypt.hash(value), { to: 'save' }) password: string; @Column({ default: 'user' }) role: string; @OneToMany(() => Post, post => post.author) posts: Post[]; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; } // Repository pattern @Injectable() export class UsersService { constructor( @InjectRepository(User) private usersRepository: Repository<User>, ) {} async findAll(): Promise<User[]> { return this.usersRepository.find(); } async findOne(id: number): Promise<User> { const user = await this.usersRepository.findOne({ where: { id }, relations: ['posts'], }); if (!user) { throw new NotFoundException(`User ${id} not found`); } return user; } } ``` ### Prisma Integration ```typescript
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る