1. Nest.js를 사용하는 이유
1) Express.js의 한계
- 바디파서, 쿠키파서 등 사용할 미들웨어들에 대해 알고있어야 코딩이 가능함.. > 복잡한 웹서버 개발 시 비효율적
- 레이어드 아키텍처 패턴 구성 시 디렉토리 구조를 명학히 설계해야 하며, 서비스 요구사항 변경 및 기획 추가 시 필요한 개념들을 새롭게 추가해야 함
2) Nest.js의 장점
- 타입스크립트 기반 > 자바스크립트에 비해 엄격한 타입 체크를 하여 여러 예외 상황을 사전에 방지
- 레이어드 아키텍처 패턴 구성 시 커맨드 하나로 대부분의 구성요소 구현 가능 (ex. Posts 컨트롤러 생성 시 nest g co posts 커맨드 사용)
- 따라서, 개발자는 웹서버의 핵심 로직 구현에만 신경쓰고 그 이외의 부분들은 Nest.js에 일임 가능
2. 간단한 코드 해부
1) 셋팅
- 터미널창에 nest 입력 > nest 커맨드에 대한 매뉴얼 제공
- nest.js로 새로운 프로잭트 생성 > npm 선택
nest new sparta-nest
2) 진입점 파일
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
- ./src/main.js > 임의로 파일 이름 변경 금지!!
- Nest.js에서 진입정으로 사용하기로 약속된 파일
- NestFactory 클래스의 create 정적함수를 통해, AppModule이라는 모듈을 루트 모듈로 사용하는 Nest.js 어플리케이션 인스턴스 새롭게 생성
3) 모듈
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
- AppModule이 정의된 app.module.ts 파일
- Nest.js는 이런 모듈 기반으로 구성되어 있음. 모듈을 새로 만들면 ./src/(모듈이름)/(모듈이름).ts 파일이 자동으로 생성됨
- 데코레이터
- @가 붙는 키워드 (ex. @Module)
- 해당 클래스나 함수가 어떤 역할을 수행하는지 Nest.js에 알려줌
- 미리 정의된 데코레이터는 각각 필요한 속성이 다름. @Module의 경우 imports, controllers, providers, exports 속성을 가질 수 있음
- 직접 데코레이터를 만드는것도 가능
4) 모듈 속성
- imports : 현재 모듈에서 사용하려는 다른 모듈들의 목록을 정의, 여기 명시된 모듈들은 주로 필요한 프로바이더(서비스)를 제공 (ex. HttpModule, TypeOrmModule 등)
- controllers : 현재 모듈과 관련된 컨트롤러의 목록 정의, 이 컨트롤러들은 해당 모듈의 요청 처리 로직을 담당
- providers : 현재 모듈에서 사용하거나 제공하는 서비스, 리포지토리, 팩토리 등의 목록을 정의, 여기 포함되는 것들은 주로 비즈니스 로직 처리나 데이터 액세스와 같은 작업을 수행
- exports : 현재 모듈에서 다른 모듈로 제공하려는 서비스의 목록을 정의, 현재 모듈 외부에서도 사용할 수 있도록 함
5) imports / exports와 service(only) / providers 의 차이
- service(only) + providers 는 서비스가 특정 모듈 내에서만 사용되고 다른 모듈에서는 사용되지 않을 때 주로 사용
- module exports + imports : 여러 모듈에서 공통적으로 사용할 때 주로 사용
6) 컨트롤러
// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
- @Controller 데코레이터를 통해 AppController 클래스가 컨트롤러 역할을 하는 것을 Nest.js에 알려줌
- 의존성 주입(constructor 부분) : 인자로 AppService 객체를 넘기면 this.appService라는 멤버 변수에 AppService 객체가 주입됨
- 컨트롤러는 반드시 서비스를 의존해야 함. 또한, 이는 생성자를 통한 의존성 주입(DI)로 해결해야 함
7) 컨트롤러의 데코레이터
- @Get : HTTP GET 으로 요청이 들어올 시 이 아래 함수로 실행함
- @Post, @Get, @Put, @Patch, @Delete 등.. 사용 가능
8) 서비스
import { Injectable } from '@nestjs/common';
@Injectable() // <- 난 Inject(주입)될 수 있어! 라고 선언하는 것이에요.
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
- @Injectable 데코레이터가 있어야 컨트롤러에서 AppController의 생성자로 AppService를 주입할 수 있음
- 서비스 객체는 실제로 리포지토리를 의존하며 비즈니스 로직을 담당 > 서비스는 리포지토리를 반드시 의존해야 하며, 이는 생성자를 통한 DI로 해결해야 함
3. IoC와 DI
1) 기존에 사용한 방법
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
// 1. 사용하고 싶은 서비스 타입 객체를 미리 선언합니다.
private appService: AppService
constructor() {
// 2. 생성자에서 실제로 사용할 서비스 객체를 직접 생성합니다.
this.appService = new AppService();
}
...
}
- 개발자가 사용할 객체를 생성부터 소멸까지 직접 관리
- AppController는 AppService의 구체적인 구현에 강하게 결합됨 > 의존하는 서비스가 변경될 경우 그에 맞춰서 코드도 수정해야 함 > 번거로움과 부작용
2) IoC (Inversion of Control, 제어 역전)
- 개발자가 사용하고 싶은 객체를 직접 생성하지 않고, 객체의 생명주기 관리 자체를 외부(위 예시의 경우 Nest.js IoC 컨테이너)에 위임
- 객체의 관리를 컨테이너에 맡겨서 제어권이 넘어감
- AppController는 AppService의 구체적인 표현보다는 인터페이스나 추상 클래스에 의존 > 서비스 자체가 변경되어도 관계없이 사용 가능 > 코드 결합도 감소, 다른 구현체로 쉽게 교체 가능
3) DI (의존성 주입)
constructor(private readonly appService: AppService) {} // 살포시 연착륙
- 의존성 주입 메커니즘으로 AppService를 AppController에 주입하여 IoC 원칙 적용
- constructor에서 AppService의 인스턴스는 Nest.js의 DI 컨테이너에 의해 생성되고 관리됨
- 따라서 개발자가 직접 new AppService와 같이 객체를 생성하거나 관리하지 않아도 됨
'TIL' 카테고리의 다른 글
TIL 240627 - TypeORM 적용 (0) | 2024.06.27 |
---|---|
TIL 240626 - 면접 예상질문 및 답변 모음 (공개모의면접 진행) (0) | 2024.06.26 |
TIL 240624 - 알고리즘 코드카타 리뷰 - 연속 부분 수열 합의 개수 (0) | 2024.06.24 |
TIL 240621 - 알고리즘 코드카타 - 괄호 회전하기 (0) | 2024.06.21 |
TIL 240620 - socket.io 적용 (2) namespace / room (0) | 2024.06.20 |