[Nestjs]프로바이더

The Dragonite·2023년 11월 30일
0

Nestjs

목록 보기
6/9
post-thumbnail

Provider

컨트롤러는 요청과 응답을 가공하고 처리하는 역할은 맡는다. 하지만 서버가 제공하는 핵심기능은 전달받은 데이터를 어떻게 비즈니스 로직으로 해결하는가이다.

이 비즈니스 로직을 해결을 수행하는 기능을 하는 것이 바로 Provider이다.

프로바이더는 service, repository, factory, helper 등의 여러 가지 형태로 구현이 가능하다.

  1. 서비스 (Service):
  • 서비스는 주로 비즈니스 로직을 처리하거나 데이터를 조작하는 데 사용됩니다.
  • 예를 들어, 사용자 데이터베이스를 다루는 사용자 서비스가 있을 수 있습니다.
// user.service.ts
import { Injectable } from '@nestjs/common';
//
@Injectable()
export class UserService {
  getUsers(): string[] {
    return ['User1', 'User2', 'User3'];
  }
  getUserById(id: number): string {
    // 로직 처리
    return `User with ID ${id}`;
  }
}
  1. 리포지토리 (Repository):
  • 리포지토리는 데이터베이스와 상호 작용하는 데 사용됩니다.
  • 예를 들어, 사용자 데이터를 데이터베이스에 저장하고 가져오는 사용자 리포지토리가 있을 수 있습니다.
// user.repository.ts
import { Injectable } from '@nestjs/common';
//
@Injectable()
export class UserRepository {
  saveUser(user: string): void {
    // 데이터베이스에 사용자 저장 로직
  }
  getUserById(id: number): string {
    // 데이터베이스에서 사용자 가져오는 로직
    return `User from database with ID ${id}`;
  }
}
  1. 팩토리 (Factory):
  • 팩토리는 인스턴스를 생성하고 반환하는 데 사용됩니다.
  • 예를 들어, 다양한 종류의 객체를 동적으로 생성하는 팩토리가 있을 수 있습니다.
// logger.factory.ts
import { Injectable } from '@nestjs/common';
//
@Injectable()
export class LoggerFactory {
  createLogger(): Logger {
    // 로거 인스턴스 생성 로직
    return new Logger();
  }
}
class Logger {
  log(message: string): void {
    console.log(message);
  }
}
  1. 헬퍼 (Helper):
  • 헬퍼는 여러 부분에서 재사용되는 유틸리티 함수 또는 메서드를 제공하는 데 사용됩니다.
  • 예를 들어, 문자열 조작이나 날짜 변환과 같은 헬퍼가 있을 수 있습니다.
// string.helper.ts
import { Injectable } from '@nestjs/common';
//
@Injectable()
export class StringHelper {
  capitalize(str: string): string {
    // 첫 글자 대문자로 변환 로직
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
}

프로바이더

본론으로 돌아와서, Nest에서 제공하는 프로바이더의 핵심은 의존성을 주입할 수 있다는 것이다.

UsersController를 다시 살펴보자

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}
  ...
  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);//+id는 숫자로만 이루어진 string을 수타입으로 바꾸는 것이다.
  }
}

컨트롤러는 비지니스 로직을 수행하지 않고 요청과 응답을 가공하는 역할을 한다.

컨트롤러에 연결된 UsersService 클래스가 이를 수행한다.

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

@Injectable()
export class UsersService {
  ...
  
  remove(id: number) {
    return `This action removes a #${id} users`;
  }
}

@Injectable 데커레이터를 통해서 UsersService 클래스가 다른 Nest 컴포넌트에 주입할 수 있는 프로바이더가 된다.

이러한 기능을 통해서 컨트롤러에서 프로바이더를 주입 받아서 사용하는 것이다.

별도의 스코프를 지정해주지 않으면 일반적으로 싱글턴 인스턴스가 생성된다고 하는데 정확히 어떤 의미인지는 잘모르겠다...


프로바이더의 등록과 사용

프로바이더 등록

프로바이더의 인스턴스 역시 모듈에서 사용할 수 있도록 등록을 해줘야 한다.
nest g s [name] 명령을 통해 자동 생성된 코드에서 모듈에 자동으로 등록해둔 것을 볼 수 있다.

@Inject()

지금까지는 constructor()를 통해 프로바이더를 주입받았는데, 프로바이더를 직접 주입받지 않고 상속 관계에 있는 자식 클래스를 주입받아 사용하고 싶은 경우가 있을 것이다. 이러한 경우에는 자식 클래스에서 부모 클래스의 함수를 호출하려면 super()를 통해서 전달을 해줘야한다. 하지만 이러한 방식은 조금 귀찮으므로 @Inject 데커레이터를 활용하면 코드를 아래와 같이 쉽게 작성할 수 있다.

export class BaseService {
  constructor(private readonly serviceA: ServiceA) {}
  
  getHello(): string {
  	...
  }
    
  doSomeFuncFromA(): string {
  	return this.serviceA.getHello()
  }
}

...

@Injectable()
export class serviceB extends BaseService {
  constructor(private readonly _serviceA: ServiceA) { 
  	super(_serviceA);
  }
  
  getHello(): string {
  	return this.doSomeFuncFromA();
  }
  
  
  ...
}

위와 같은 코드를 아래와 같이 바꿀 수 있을 것이다.

export class BaseService{
  @Inject(ServiceA) private readonly serviceA: ServiceA;
  ...
  
  doSomeFuncFromA(): string {
  	return this.serviceA.getHello();
  }
}

@Injectable()
export class ServiceB extends BaseService {
  getHello(): string {
  	return this.doSomeFuncFromA();
  }
}

단, 상속 관계에 있지 않는 경우에는 속성 기반 주입을 사용하는 것 보단 생성자 기반 주입을 사용하는 것이 권장된다.


이 포스트는 위 책을 기반으로 작성하고 있습니다...

0개의 댓글

관련 채용 정보