Nest.js에 대해서 알아보자 - Provider편
이전 장에서는 Controller에 대한 개념을 다뤄보았고, 이번에는 Provider에 대해서 다뤄볼 예정입니다.
혹시 Contorller에 대한 이해가 부족하신 분들은 이전 포스트를 확인해보시면 Provider에 대한 이해에 도움이 되실 것이라고 생각합니다.
Nest.js에 대해서 알아보자 - Controller편 (tistory.com)
Nest.js에 대해서 알아보자 - Controller편
개인적인 공부를 위해 공식문서를 읽고 저의 해석을 곁들였습니다.틀린 부분이 있다면 언제든 피드백 환영입니다.컨트롤러의 정의컨트롤러는 들어오는 요청을 처리하고 클라이언트에 응답
humor12.tistory.com
Provider
저희는 이제 Controller는 들어오는 요청을 처리하고 클라이언트에 응답을 반환하는 일을 담당한다는 것을 알고 있습니다.
그러나 Controller 가 하나부터 열까지 모든 것을 처리하면 코드의 가독성이 떨어지고 유지보수에 어려움을 겪을 수도 있습니다. 그렇기에 Controller는 HTTP 요청을 처리하고 더 복잡한 작업을 Provider에게 위임해야 합니다.
Provider는 서비스, 리포지토리, 팩토리 등과 같은 의존성을 주입하고 관리하는 객체를 의미합니다. 일반적으로 Nest.js 애플리케이션의 클래스들은 @Injectable() 데코레이터를 사용하여 의존성 주입이 가능하게 되고, 이 클래스들이 바로 Provider가 됩니다.
Provider 사용 예시
백문이불여일견이라고 하였습니다. 바로 Provider에 대한 예제 코드를 통해 설명을 이어나가겠습니다.
1. 서비스 클래스 생성
저는 Nest.js cli 명령어를 이용하여 서비스 클래스를 생성하도록 하겠습니다. 만약 패키지 설치가 안 되신 분들은 아래의 명령어를 콘솔창에 입력해주세요.
npm i -g @nestjs/cli
그리고 cli에 다음과 같은 명령어를 통해 서비스를 생성해봅니다.
nest g s cats
그럼 이제 우리는 cats.service.ts 라는 파일이 하나 생성된 것을 확인해볼 수 있습니다.
아래의 코드는 하나의 속성과 두 개의 메소드를 가진 기본 클래스입니다. 여기서 새로운 점을 꼽자면, 위에서 언급했던 @Injectable() 데코레이터를 사용한다는 것입니다. @Injectable() 데코레이터를 사용해 클래스를 Provider로 만들 수 있으며, 이를 모듈에서 등록한 후 필요한 곳에 주입할 수 있습니다.
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat) {
this.cats.push(cat);
}
findAll(): Cat[] {
return this.cats;
}
}
위 코드를 에러 없이 동작시키고 싶으시다면, cat의 속성에 대한 타입을 정의하셔야합니다. 다음과 같이 interface를 작성하고 cat 속성의 type을 정의합니다.
export interface Cat {
name: string;
age: number;
breed: string;
}
2. Cats 컨트롤러 생성
이번에는 아래의 명령어를 통해 Cats 컨트롤러를 생성해보도록 하겠습니다.
nest g co cats
컨트롤러가 생성되었다면, 아래와 같이 코드를 작성해줍니다.
여기서 유의할 점은 바로 위에서 만들었던 CatsService를 생성자를 통해 주입을 해주고 있다는 점입니다. 이렇게 의존성 주입을 해주는 이유가 따로 있습니다. 바로 의존성 주입(Dependency Injection, DI)을 활용하여 클래스 간의 의존성을 효율적으로 관리하고, 느슨한 결합(Loose Coupling)을 유지하기 위함입니다. 또한, 필자가 강의를 들었을 때 들은 이야기로는 의존성 주입을 사용하면 모의 객체(Mock)를 통해 주입된 서비스를 테스트할 수 있어 테스트하기에도 용이하다는 이야기를 들었습니다.
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
}
3. 모듈에서 Provider 등록
이제는 주입이 성공적으로 가능하게끔 하기 위해서는 위에서 만들었떤 서비스를 Nest에 등록해야 합니다. 기존에 만들어져있는
app.module.ts 파일에서 아래와 같이 Controller와 CatsService가 배열 안에 들어가 있는지를 확인해줍니다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class AppModule {}
마치며...
이렇게 함으로써 우리는 Controller는 주로 요청을 처리하고, 서비스는 복잡한 비즈니스 로직을 담당하도록 만들어 단일 책임 원칙을 지키도록 할 수 있다는 것을 알게 되었습니다.
다음에는 Module편으로 찾아뵙도록 하겠습니다. 감사합니다.