NestJS는 모듈화된 아키텍처를 채택한 서버사이드 프레임워크로, 그 핵심 개념 중 하나가 바로 Providers입니다. Providers는 의존성 주입(Dependency Injection, DI)을 기반으로 다양한 서비스나 객체를 서로 연결하는 역할을 합니다. 이를 통해 개발자는 객체 간의 복잡한 관계를 Nest 런타임에 위임할 수 있습니다. 이번 포스팅에서는 Providers와 서비스(Service) 패턴을 중심으로 NestJS의 기본 개념과 적용 방법에 대해 설명하겠습니다.
NestJS에서 Providers는 서비스, 레포지토리, 팩토리, 헬퍼 클래스 등 다양한 형태로 정의될 수 있습니다. Providers는 단순한 자바스크립트 클래스에 @Injectable() 데코레이터를 붙여 정의하며, 이 클래스를 다른 곳에서 의존성으로 주입하여 사용할 수 있습니다. 이를 통해 객체 간의 복잡한 관계를 Nest의 IoC(Inversion of Control) 컨테이너가 관리하게 됩니다.
서비스는 일반적으로 데이터를 처리하거나 로직을 실행하는 곳으로, 컨트롤러에서 더 복잡한 작업을 서비스로 위임하는 패턴을 따릅니다. 예를 들어, CatsService는 데이터 저장 및 검색 작업을 담당하며, 이는 CatsController에서 주입받아 사용됩니다.
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;
}
}
이처럼 간단한 서비스 클래스는 데이터를 저장하는 create()와 저장된 데이터를 반환하는 findAll() 메서드를 가집니다. 이 클래스는 @Injectable() 데코레이터를 사용해 Nest IoC 컨테이너에 의해 관리되며, 다른 클래스에서 의존성으로 주입받아 사용됩니다.
서비스를 생성한 후, 이를 컨트롤러에서 사용할 수 있도록 의존성으로 주입해 보겠습니다. 컨트롤러는 HTTP 요청을 처리하고, 복잡한 비즈니스 로직은 서비스로 위임하는 역할을 합니다.
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();
}
}
CatsController는 생성자에서 CatsService를 주입받아 사용합니다. @Post()와 @Get() 데코레이터를 사용하여 HTTP 요청에 대한 응답으로 create()와 findAll() 메서드를 호출합니다. 주입은 매우 간단하며, 타입만 명시해주면 Nest가 자동으로 의존성을 해결해 줍니다.
NestJS는 의존성 주입 디자인 패턴을 핵심으로 채택하고 있습니다. 클래스에서 필요한 의존성(서비스, 레포지토리 등)은 생성자에 선언하는 것만으로 자동으로 해결되며, 이를 통해 객체 간의 결합도를 낮추고 재사용성을 높일 수 있습니다. 기본적으로, Nest는 싱글톤 패턴을 사용하여 각 서비스를 애플리케이션 전역에서 하나의 인스턴스로 사용합니다.
서비스를 정의하고 컨트롤러에서 사용하려면, 해당 서비스가 Nest 모듈에 등록되어야 합니다. 아래는 app.module.ts 파일에서 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 {}
providers 배열에 CatsService를 추가하면, Nest는 해당 서비스를 자동으로 관리하고 의존성을 해결해 줍니다.
NestJS에서 Providers와 서비스 패턴은 애플리케이션을 모듈화하고, 객체 간의 복잡한 의존성을 간단하게 관리할 수 있는 강력한 도구입니다. 이를 통해 개발자는 SOLID 원칙을 준수하며 확장 가능하고 유지보수 가능한 코드를 작성할 수 있습니다.
NestJS의 IoC 컨테이너와 의존성 주입 시스템을 이해하고 적절히 활용하면, 훨씬 더 깔끔하고 유지 보수가 용이한 애플리케이션을 개발할 수 있을 것입니다.