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
آخر نشاط في المصدر
٣١ مارس ٢٠٢٦ في ١٩:١٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٩
التفرعات
١

خيارات التثبيت

يُحدَّد 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