본문 바로가기
JS & TS/Nest.js

DI with Nest.js

by devson 2021. 1. 2.

(2020-05-23에 작성한 글입니다.)

 

코드는 여기에서 확인할 수 있다.

 


 

Nest.js는 기본적으로 DI를 지원하기 때문에 별도의 library를 설치하지 않아도 DI를 적극적으로 사용할 수 있게 도와준다.

 

Hexagonal architecture와 같이 특정 인프라 스트럭쳐에 의존하지 않는 코드를 작성한다면
Repository와 같이 특정 인프라 스트럭쳐를 사용하는 기능은 interface로 추상화하고 이에 대한 구현은 클래스에 할 것이다.

 

사용자 기능을 구현하는 Nest.js application을 만든다면 아래와 같이 시작할 수 있을 것이다.

// src/user/UserService.ts

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

@Injectable()
export class UserService {
  constructor(
    private readonly userRepository: UserRepository
  ) {}

  getUser(id: number): User {
    return this.userRepository.findById(id);
  }
}

 

// src/user/UserRepository.ts

export interface UserRepository {
  findById(id: number): User | null;
}

 

// src/user/InMemoryUserRepository.ts

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

@Injectable()
export class InMemoryUserRepository implements UserRepository {
  private readonly users: { [userId: string]: User } = {};

  findById(id: number): User | null {
    const user = this.users[id];
    return !!user ? user : null;
  }
}

 

그리고 UserModule을 만들어서 위 component들을 Nest.js가 DI를 할 수 있도록 설정하자.

// src/user/user.module.ts

import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [],
  providers: [
    UserService,
    UserRepository
  ],
})
export class UserModule {}

 

하지만 위와 같이 UserRepository interface를 providers에 지정하면 다음과 같이 compile 에러가 난다.

 

그러면 구현 클래스를 provider로 UserModule의 providers에 지정하면 어떨까?

// src/user/user.module.ts

import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [],
  providers: [
    UserService,
    InMemoryUserRepository
  ],
})
export class UserModule {}

AppModuleUserModule을 추가하고 실행해보자.

// src/app.module.ts

import { Module } from '@nestjs/common';

@Module({
  imports: [
    UserModule
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

애플리케이션을 실행하면 아래와 같이 UserServiceUserRepository dependency를 injection 받아야하는데 해당 dependency를 찾을 수 없다는 에러메시지를 볼 수 있을 것이다.

$ npm run start

> interface-di@0.0.1 start /Users/son/dev/study/what_i_study/JS/NestJS/interface-di
> nest start

[Nest] 46016   - 05/23/2020, 3:53:46 PM   [NestFactory] Starting Nest application...
[Nest] 46016   - 05/23/2020, 3:53:46 PM   [ExceptionHandler] Nest can't resolve dependencies of the UserService (?). Please make sure that the argument Object at index [0] is available in the UserModule context.

 

Nest.js는 interface DI를 지원하지 않는 것일까?
이에 대한 해답은 Nest.js issue: Typescript - Interface injecting에서 확인할 수 있다.

 

일단 interface를 providers에 지정할 수 없는 이유는 interface는 개발 시에만 존재하기 때문에 값으로 사용할 수가 없다는 것이다.


실제로 컴파일된 interface를 파일을 확인하면 다음과 같이 비어있는 것을 확인할 수 있다.

// dist/user/UserRepository.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=UserRepository.js.map

 

Nest.js의 창시자인 kamilmysliwiec 역시 ts types는 컴파일이 되면 사라지기 때문에 인해서 interface로 DI를 할 수 없다고 못박았다.

 

interface DI를 하고자 하면 다음과 같이 Nest.js의 provider를 사용한 약간의 스킬로 구현할 수는 있다.

import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [],
  providers: [
    UserService,
    // provide: interface, useClass: DI 하려는 interface 구현체
    { provide: 'UserRepository', useClass: InMemoryUserRepository }
  ],
})
export class UserModule {}

 

import { Injectable, Inject } from '@nestjs/common';

@Injectable()
export class UserService {
  constructor(
    // provide에서 설정한 string 값을 @Inject에 적어준다
    @Inject('UserRepository') private readonly userRepository: UserRepository
  ) {}

  getUser(id: number): User {
    return this.userRepository.findById(id);
  }
}

위와 같이 설정한 후 애플리케이션을 실행하면 정상적으로 실행되는 것을 볼 수 있을 것이다.

$ npm run start

> interface-di@0.0.1 start /Users/son/dev/study/what_i_study/JS/NestJS/interface-di
> nest start

[Nest] 46301   - 05/23/2020, 3:58:35 PM   [NestFactory] Starting Nest application...
[Nest] 46301   - 05/23/2020, 3:58:35 PM   [InstanceLoader] AppModule dependencies initialized +17ms
[Nest] 46301   - 05/23/2020, 3:58:35 PM   [InstanceLoader] UserModule dependencies initialized +0ms
[Nest] 46301   - 05/23/2020, 3:58:35 PM   [NestApplication] Nest application successfully started +8ms

'JS & TS > Nest.js' 카테고리의 다른 글

AdminBro로 Nest.js admin 쉽게 만들기  (8) 2021.05.29
Nest.js Docker image 만들기  (0) 2021.01.02

댓글