소스 코드

[리포지 링크]

들어가기 전에

이번 장에서는 지난 시간에 만든 1단계 API 만들기 프로젝트에 ‘2단계 의존성 주입’을 다뤄보도록 하겠다.

1단계 API 만들기 2단계 의존성 주입 3단계 몽고DB 연동
1. 프로젝트 생성하기
2. 컨트롤러 만들기
3. 블로그 API 작성하기
4. 메모리와 파일로 블로그 API 만들기
1. 의존성 주입 설정하기
2. 서비스에 리포지토리 의존성 주입하기
3. 컨트롤러에 서비스 의존성 주입하기
1. 의존성 설치하기
2. 스키마 만들기
3. 몽고DB 리포지토리 생성하기
4. 서비스에서 몽고DB를 사용하도록 변경하기

1. 의존성과 의존성 주입 이란?

의존성

클래스가 다른 클래스의 메서드나 속성을 사용하면, 한 클래스가 다른 클래스에 ‘의존’한다고 한다.

의존성 주입

객체 지향 프로그래밍에서 매우 중요한 디자인 패턴 중 하나로, 특정 클래스가 다른 클래스와의 의존성 없이 작동할 수 있도록 하는 기법이다.

2. 의존성 주입이 필요한 이유?

지금까지 만든 컨트롤러, 서비스, 리포지토리는 서로 의존 관계이다. 컨트롤러는 서비스를 사용하고, 서비스는 리포지토리를 사용한다. 그리고 각 단계마다 객체를 생성하여 사용했는데, 이러한 방식은 확장성(수십 수백 클래스가 있다면 그때마다 생성할것인가?)에서 아쉬움이 있다.

이러한 문제를 해결하기 위한 원칙이 있는데, 제어의 역전 원칙이다. 제어의 역전은 개발자가 제어했던 객체 생성의 역할을 프레임워크가 생성한 컨테이너가 의존성을 관리하는 것을 말한다.

NestJS에서 의존성 주입을 하는 방법은 간단하다. 주입하고 싶은 클래스에 @Injectable 데코레이터를 붙이기만 하면 된다. 예제에서는 서비스와 리포지토리를 다른 클래스에서 사용하므로 의존성 주입 대상이 된다.

3. 의존성 주입을 어디에하면 될까?

순서 1. 컨트롤러에서 서비스에 의존하고, 서비스에서 리포지토리에 의존하고 있기 때문에 의존성을 ‘서비스’와 ‘리포지토리’에 주입해야 한다.

// blog.repository.ts

import { Injectable } from "@nestjs/common";
// ... 생략 ...

@Injectable() // 추가
export class BlogFileRepository implements BlogRepository {
// ... 생략 ...
// blog.service.ts

import { Injectable } from '@nestjs/common'; // 추가

@Injectable()
export class BlogService {
    // 1. 기존 생성자 코드 삭제
    // blogRepository: BlogRepository;
    // constructor() {
    //     this.blogRepository = new BlogFileRepository();
    // }

    // 2. 생성자를 통한 의존성 주입
    constructor(private blogRepository: BlogFileRepository) { }

1~2번. 클래스의 생성자(constructor())에 매개변수로 설정된 타입이 프로바이더로 설정된 타입 중 하나라면, NestJS에서 자동으로 필요한 객체를 주입해준다. **그런데, BlogFileRepository가 '인터페이스'이므로 클래스를 생성할 수 없다. 따라서 의존성 주입을 위해, '클래스'로 타입을 변경해줘야 한다.**

2번. constructor(private blogRepository: BlogFileRepository) { } 가 복잡해보인다. 이 코드를 풀어서 쓰면 아래와 같다.

private blogRepository: BlogFileRepository;
constructor(blogRepository: BlogFileRepository) {
	// 1. 클래스 멤버 변수에 주입받은 blogRepository 할당
	this.blogRepository = blogRepository;
}

순서 2. 컨트롤러에서 서비스에 의존하는데, 컨트롤러(blog.controller.ts)에서 생성자로 되어 있던 부분을 의존성 주입을 받을 수 있도록 변경한다.

// blog.controller.ts

@Controller('blog')
export class BlogController {

    // 1. 기존 생성자 코드 삭제
    // blogService: BlogService;
    // constructor() {
    //     this.blogService = new BlogService();
    // }

    // 2. 생성자를 통한 의존성 주입
    constructor(private blogService: BlogService) { }

1~2번. 클래스의 생성자(constructor())에 매개변수로 설정된 타입이 프로바이더로 설정된 타입 중 하나라면, NestJS에서 자동으로 필요한 객체를 주입해준다.

순서 3. 위까지 코드를 작성했다면, blog.service.ts 에서 에러가 발생한다. 이유는 NestJS에서 의존성 주입을 하는 타입인지 알려주어야 하기 때문이다. 이를 위해 @Injectable을 붙였던 두 개의 클래스(BlogService, BlogFileRepository)를 ‘프로바이더’로 설정한다.

// app.module.ts
import { BlogFileRepository } from "./blog.repository"; // 추가

@Module({
  imports: [],
  controllers: [BlogController],
  providers: [BlogService, BlogFileRepository] // 1. 프로바이더 설정
})
export class AppModule { }

1번. BlogService, BlogFileRepository에 @Injectable을 붙였으므로 프로바이더가 되었다. 앱이 실행될 때 의존성 주입을 하도록 클래스 정보를 추가한다.

순서 4. 테스트를 하면 정상작동함을 확인할 수 있다.

image-20230823172937460

참고

다음에 다루게 될 것

  • NestJS로 블로그 API 만들기 - 3단계 몽고DB 연동

댓글남기기