14.1 NestJS 소개 — 데코레이터 기반 TypeScript 프레임워크
NestJS란?
NestJS는 TypeScript로 작성된 Node.js 서버 프레임워크입니다. Angular에서 영감을 받아 **데코레이터(Decorator)**와 **의존성 주입(Dependency Injection)**을 중심으로 설계되었습니다.
특징:
- TypeScript-first: 완전한 타입 안전성
- 데코레이터 기반 선언적 코드
- 모듈 시스템으로 관심사 분리
- Express/Fastify 위에서 동작
- 테스트 용이성 (DI 컨테이너)
설치 및 프로젝트 생성
npm install -g @nestjs/cli
nest new my-project
cd my-project
npm run start:dev
프로젝트 구조
src/
├── app.module.ts # 루트 모듈
├── app.controller.ts # 루트 컨트롤러
├── app.service.ts # 루트 서비스
├── main.ts # 진입점
└── users/
├── users.module.ts
├── users.controller.ts
├── users.service.ts
└── dto/
├── create-user.dto.ts
└── update-user.dto.ts
핵심 구성 요소
Module (모듈)
// users/users.module.ts
import { Module } from '@nestjs/common'
import { UsersController } from './users.controller'
import { UsersService } from './users.service'
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // 다른 모듈에서 사용 가능하게 내보내기
})
export class UsersModule {}
// app.module.ts (루트 모듈)
import { Module } from '@nestjs/common'
import { UsersModule } from './users/users.module'
import { AuthModule } from './auth/auth.module'
@Module({
imports: [UsersModule, AuthModule],
})
export class AppModule {}
Controller (컨트롤러)
// users/users.controller.ts
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
HttpCode,
HttpStatus,
} from '@nestjs/common'
import { UsersService } from './users.service'
import { CreateUserDto } from './dto/create-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'
@Controller('users') // /users 경로
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(@Query('page') page = '1', @Query('limit') limit = '10') {
return this.usersService.findAll({
page: parseInt(page),
limit: parseInt(limit),
})
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(id)
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto)
}
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(id, updateUserDto)
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string) {
return this.usersService.remove(id)
}
}
Service (서비스)
// users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common'
import { CreateUserDto } from './dto/create-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'
interface User {
id: string
name: string
email: string
createdAt: Date
}
interface PaginationParams {
page: number
limit: number
}
@Injectable()
export class UsersService {
private users: User[] = []
findAll({ page, limit }: PaginationParams) {
const start = (page - 1) * limit
return {
data: this.users.slice(start, start + limit),
total: this.users.length,
page,
limit,
}
}
findOne(id: string): User {
const user = this.users.find(u => u.id === id)
if (!user) {
throw new NotFoundException(`사용자 ID ${id}를 찾을 수 없습니다.`)
}
return user
}
create(createUserDto: CreateUserDto): User {
const user: User = {
id: Date.now().toString(),
...createUserDto,
createdAt: new Date(),
}
this.users.push(user)
return user
}
update(id: string, updateUserDto: UpdateUserDto): User {
const user = this.findOne(id)
Object.assign(user, updateUserDto)
return user
}
remove(id: string): void {
const index = this.users.findIndex(u => u.id === id)
if (index === -1) {
throw new NotFoundException(`사용자 ID ${id}를 찾을 수 없습니다.`)
}
this.users.splice(index, 1)
}
}
main.ts 설정
// main.ts
import { NestFactory } from '@nestjs/core'
import { ValidationPipe } from '@nestjs/common'
import { AppModule } from './app.module'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
// 전역 유효성 검사 파이프
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // DTO에 없는 필드 제거
forbidNonWhitelisted: true, // DTO에 없는 필드 오류
transform: true, // 자동 타입 변환
})
)
// CORS 설정
app.enableCors({
origin: process.env.ALLOWED_ORIGIN ?? '*',
})
// API 접두사
app.setGlobalPrefix('api')
await app.listen(process.env.PORT ?? 3000)
console.log(`🚀 서버 실행: http://localhost:${process.env.PORT ?? 3000}`)
}
bootstrap()
고수 팁
NestJS CLI 주요 명령어
# 모듈 생성
nest generate module users
nest g mo users # 단축형
# 컨트롤러 생성
nest generate controller users
nest g co users
# 서비스 생성
nest generate service users
nest g s users
# 전체 CRUD 리소스 생성
nest generate resource users
nest g res users # module + controller + service + DTO 한 번에