728x90
12주차 NestJS 정리
1. 프레임워크란?
- 개발을 쉽게 할 수 있도록 제공되는 기본 구조 및 재사용 가능한 코드, 라이브러리의 집합
- 예시: Express, Next.js, NestJS
2. NestJS를 사용하는 이유
- 구조적이고 체계적인 아키텍처
- 기능을 모듈 단위로 설계 → 이해하기 쉬움
- 대규모 프로젝트에서 유지보수 용이
- 의존성 주입(DI) 방식 → 테스트 용이 & 일관된 틀 유지
- 기업에서 활발히 사용 중
- 최신 기술과 통합이 쉽고 빠른 개발 가능
✅ Express와의 차이점
- Express: 자유도가 높음 → 프로젝트가 커질수록 유지보수 어려움
- NestJS: 구조화된 방식 제공 → 유지보수 & 협업 용이
3. NestJS 기본 개념 및 아키텍처
NestJS는 모듈(Module) 단위로 기능을 나누어 구성
① Module (모듈)
- 하나의 독립적인 기능 블록 (레고처럼 조립 가능)
- 모듈 안에는 컨트롤러, 서비스, 레포지토리 등이 포함
예시)
- User 모듈: 사용자 관련 기능
- Auth 모듈: 인증 관련 기능
- Order 모듈: 주문 관련 기능
② Controller (컨트롤러) - 요청 처리
- 사용자 요청을 받아 서비스로 전달하는 역할
- Express의 req, res 역할을 @Controller()가 담당
✅ 컨트롤러 예제
import { Controller, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
async createUser(@Body() createUserDto: CreateUserDto) {
try {
const user = await this.userService.createUser(createUserDto);
return { message: '회원가입 성공', user };
} catch (error) {
return { message: error.message };
}
}
}
- @Controller('users'): /users 경로를 처리
- @Post(): POST 요청을 받음
- 핵심 로직은 서비스(Service)에서 처리하고, 컨트롤러는 전달 역할
③ Service (서비스) - 비즈니스 로직
- 실제 비즈니스 로직을 담당
- @Injectable() 데코레이터 사용
- 데이터 검증, 중복 체크, 암호화 등의 핵심 동작 처리
✅ 서비스 예제
import { Injectable, ConflictException } from '@nestjs/common';
import { UserRepository } from './user.repository';
import { CreateUserDto } from './dto/create-user.dto';
import * as bcrypt from 'bcrypt';
import { User } from './user.entity';
@Injectable()
export class UserService {
constructor(private readonly userRepository: UserRepository) {}
async createUser(userDto: CreateUserDto): Promise<User> {
// 중복 이메일 체크
const existingUser = await this.userRepository.findByEmail(userDto.email);
if (existingUser) {
throw new ConflictException('이미 가입된 이메일입니다.');
}
// 비밀번호 해싱
const hashedPassword = await bcrypt.hash(userDto.password, 10);
// 사용자 데이터 생성
const newUser: User = {
id: Date.now(),
name: userDto.name,
email: userDto.email,
password: hashedPassword,
};
// 저장 후 결과 반환
return this.userRepository.save(newUser);
}
}
- @Injectable(): NestJS가 서비스 클래스를 관리
- 비즈니스 로직을 수행하고, 레포지토리로 데이터를 전달
④ Repository (레포지토리) - 데이터베이스 처리
- 데이터베이스와 직접적인 CRUD 작업 담당
- 서비스(Service)에서 호출하여 사용
4. Dependency Injection (의존성 주입, DI)
- 객체가 직접 필요한 의존성을 생성하지 않고, 외부에서 주입받는 방식
- 이를 통해 코드 결합도 감소(Loose Coupling) & 유지보수 용이
✅ 의존성 주입 예제
@Injectable()
export class UserService {
constructor(private readonly userRepository: UserRepository) {} // DI를 통해 자동 주입
findAll() {
return this.userRepository.findAll();
}
}
- UserService는 UserRepository가 필요하지만 직접 생성하지 않음
- NestJS의 IoC 컨테이너가 자동으로 주입
IoC (Inversion of Control) 컨테이너
- UserService는 UserRepository가 필요하다고 선언
- NestJS IoC 컨테이너가 UserRepository를 자동 생성하여 UserService에 주입
- UserService에서 UserRepository 사용 가능
5. DTO (Data Transfer Object) - 데이터 검증
- 데이터 유효성 검사 및 변환을 수행
- class-validator를 사용하여 데이터 검증
✅ DTO 예제
import { IsString } from 'class-validator';
export class CreateUserDto {
@IsString()
name: string;
}
- @IsString(): name이 문자열인지 검증
✅ 컨트롤러에서 DTO 사용
import { Body, Controller, Post } from '@nestjs/common';
import { CreateUserDto } from './create-user.dto';
@Controller('users')
export class UsersController {
@Post()
createUser(@Body() createUserDto: CreateUserDto) {
return `User ${createUserDto.name} created!`;
}
}
전역 적용 방법 (main.ts)
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe()); // 전역적으로 DTO 검증 적용
await app.listen(3000);
}
bootstrap();
- app.useGlobalPipes(new ValidationPipe()): 모든 요청에 DTO 검증 적용
6. Singleton 패턴
- 하나의 인스턴스를 생성하여 공유하는 디자인 패턴
- NestJS의 @Injectable()은 기본적으로 싱글톤으로 동작
✅ 싱글톤 예제
class SingletonLogger {
private static instance: SingletonLogger;
private constructor() {}
static getInstance(): SingletonLogger {
if (!SingletonLogger.instance) {
SingletonLogger.instance = new SingletonLogger();
}
return SingletonLogger.instance;
}
log(message: string) {
console.log(message);
}
}
const logger1 = SingletonLogger.getInstance();
const logger2 = SingletonLogger.getInstance();
console.log(logger1 === logger2); // true (같은 객체)
- NestJS에서는 @Injectable()을 사용하면 자동으로 싱글톤 관리
✅ NestJS에서 싱글톤 사용 예제
@Injectable()
export class LoggerService {
log(message: string) {
console.log(`[LOG]: ${message}`);
}
}
- 여러 컨트롤러에서 같은 LoggerService 인스턴스를 공유
💡 NestJS 핵심 개념 요약
개념 역할
Module | 기능을 독립적인 블록으로 나누어 관리 |
Controller | 사용자 요청을 받아 서비스에 전달 |
Service | 핵심 비즈니스 로직 수행 |
Repository | 데이터베이스 처리 (CRUD) |
DI | 의존성 자동 주입 (Loose Coupling) |
DTO | 데이터 검증 및 변환 |
Singleton | 인스턴스를 하나만 생성해 관리 |
'게임서버-스파르타코딩NodeJs_7기 > 분반 수업 Basic-A' 카테고리의 다른 글
TypeORM (0) | 2025.02.18 |
---|---|
베이직 250121 타입스크립트 (0) | 2025.01.21 |
9주차 Jest - 테스트(작성중) (0) | 2025.01.14 |
(수정중)코드 분리 - Layered Architecture Pattern (0) | 2025.01.07 |
(진행)7주차 - Acces Token / Refresh Token, API, Insomnia (0) | 2025.01.01 |