building-nestjs-apis
SKILL.md
NestJS
Quick Start
import { Controller, Get, Module, NestFactory } from '@nestjs/common';
@Controller('health')
class HealthController {
@Get()
check() {
return { status: 'ok' };
}
}
@Module({ controllers: [HealthController] })
class AppModule {}
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
Features
| Feature | Description | Guide |
|---|---|---|
| Modules | Dependency injection, providers | MODULES.md |
| Controllers | Routes, validation, guards | CONTROLLERS.md |
| Services | Business logic, repositories | SERVICES.md |
| Database | TypeORM, Prisma integration | DATABASE.md |
| Auth | Passport, JWT, guards | AUTH.md |
| Testing | Unit, e2e with Jest | TESTING.md |
Common Patterns
Controller with Validation
@Controller('users')
@UseGuards(JwtAuthGuard)
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
@Roles('admin')
findAll(@Query() query: PaginationDto) {
return this.usersService.findAll(query);
}
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.usersService.findOne(id);
}
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
}
Service with Repository
@Injectable()
export class UsersService {
constructor(private readonly usersRepo: UsersRepository) {}
async findAll(query: PaginationDto) {
const [users, total] = await this.usersRepo.findAllWithCount({
skip: query.skip,
take: query.limit,
});
return { data: users, total, page: query.page };
}
async findOne(id: string) {
const user = await this.usersRepo.findOne({ where: { id } });
if (!user) throw new NotFoundException('User not found');
return user;
}
async create(dto: CreateUserDto) {
const exists = await this.usersRepo.findByEmail(dto.email);
if (exists) throw new ConflictException('Email in use');
return this.usersRepo.save(this.usersRepo.create(dto));
}
}
DTO with Validation
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(2)
name: string;
@IsString()
@MinLength(8)
@Matches(/^(?=.*[A-Z])(?=.*\d)/, {
message: 'Password must contain uppercase and number',
})
password: string;
@IsOptional()
@IsEnum(UserRole)
role?: UserRole;
}
Workflows
API Development
- Create module with
nest g module [name] - Create controller and service
- Define DTOs with class-validator
- Add guards for auth/roles
- Write unit and e2e tests
Module Structure
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService, UsersRepository],
exports: [UsersService],
})
export class UsersModule {}
Best Practices
| Do | Avoid |
|---|---|
| Use dependency injection | Direct instantiation |
| Validate with DTOs | Trusting input |
| Use guards for auth | Auth logic in controllers |
| Use interceptors for cross-cutting | Duplicating logging/transform |
| Write unit + e2e tests | Skipping test coverage |
Project Structure
src/
├── main.ts
├── app.module.ts
├── common/
│ ├── decorators/
│ ├── guards/
│ ├── interceptors/
│ └── pipes/
├── config/
├── users/
│ ├── users.module.ts
│ ├── users.controller.ts
│ ├── users.service.ts
│ ├── dto/
│ └── entities/
└── auth/
├── auth.module.ts
├── strategies/
└── guards/
For detailed examples and patterns, see reference files above.
Weekly Installs
4
Repository
doanchienthangdev/omgkitGitHub Stars
3
First Seen
Feb 20, 2026
Security Audits
Installed on
opencode4
gemini-cli4
antigravity4
github-copilot4
codex4
amp4