(NestJS-기초강의) 8. Service (Feat. Provider)

이번 NestJS강좌에서는 비즈니스 로직이 구현되는 Service가 무엇인지, 어떻게 동작하는지, 그리고 사용법에 대해 알아보겠습니다.

Provider란 무엇인가

기본적인 Nest의 많은 클래스(services, repositories, factories, helpers 등)은 Provider로 취급될 수 있습니다.

Provider의 주요 개념은 의존성으로 주입(Inject)될 수 있다는 것입니다.

이를 이용하여 객체들은 서로 다양한 관계를 만들며, 이러한 연결의 기능은 대부분 Nest 런타임에 위임하게 됩니다.

Controller는 HTTP 요청을 처리하고 비즈니스로직의 수행은 Provider에게 위임합니다.

Provider는 Module에서 선언하는 일반 javascript class 입니다.

Service란 무엇인가?

Provider는 앞서 소개한 것처럼 Service를 포함하며, Service는 비즈니스 로직을 수행합니다.
(NestJS는 Service를 캡슐화하고 재사용 가능하게 합니다.)

서비스는 일반적으로 단일 책임 원칙에 따라 애플리케이션의 여러 부분 간에 데이터를 공유하고 조작하는 데 사용됩니다.

Service 생성 및 사용

Nest CLI 통해 service 만들기

6. 모듈(Module) 에서 확인할 수 있듯이 Nest CLI의 다음 명령어를 통해 service를 추가할 수 있습니다.

$ nest g service users

@Injectable() Decorator

아래와 같이 생성된 service는 @Injectable() 이란 Decorator를 사용하여,
이 Service (UsersService)가 Nest IoC 컨테이너에서 관리하는 Class 임을 Meta data를 첨부하여 선언한 것 입니다.

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

@Injectable()
export class UsersService {}

Controller와 연결

Controller에서 Service를 사용하기 위하여 interface(model)과 method를 정의하고 연결합니다.

Interface(model) 추가

Service를 Controller와 연결하기에 앞서 주고 받을 데이터 타입(interface)를 선언합니다.

src/users/interfaces/user.interface.ts

export interface User {
  id: string;
  name: string;
  age: number;
}
비즈니스 로직 구현

Controller에서 사용하기 위하여 Service에 비즈니스 로직을 수행할 method를 추가합니다.

이 때, 주고받는 데이터는 앞 서 선언한 interface를 사용합니다.

/src/users/users.service.ts

import { Injectable } from '@nestjs/common';
import { User } from './interfaces/user.interface';

@Injectable()
export class UsersService {
  private readonly users: User[] = [];

  add(user: User) {
    this.users.push(user);
  }

  findAll(): User[] {
    return this.users;
  }
}
Controller에서 Service의 비즈니스 로직 사용

Controller에서 요청 받은 비즈니스 로직이 실행되도록 라우팅 합니다.

아래 예제에서 constructor(private readonly usersService: UsersService) {} 를 통해, UsersService 인스턴스를 생성하고 반환하여 usersService를 통해 사용할 수 있게 해줍니다.
(이는 싱글톤으로 생성하여 Instance를 반환하여 Controller 생성자에 전달되는 것으로 상세 로직은 Angluer 문서에 잘 나와 있습니다.)

그렇게 전달받은 usersService 를 이용해 정의한 UserService의 비즈니스 로직들을 수행하도록 라우팅 합니다.

/src/users/users.controller.ts

import { Controller, Get, Post, Param, Req, Body } from '@nestjs/common';
import { Request } from 'express';

import { UsersService } from './users.service';

import { CreateUserDto } from './dtos/create-user.dto';
import { User } from './interfaces/user.interface';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  async create(@Body() createUserDto: CreateUserDto) {
    console.log(createUserDto);
    return this.usersService.add(createUserDto);
  }

  @Get('all-users')
  async findAll(@Req() request: Request): Promise<User[]> {
    console.log(request.headers);
    return this.usersService.findAll();
  }

  @Get(':id')
  async getUserById(@Param() params): Promise<string> {
    return `This user has id ${params.id}`;
  }
}

이렇게 정의된 서비스는 앞서 NestJS CLI를 통해 추가할 때, 다음과 같이 Module의 providers 특성에 등록되었습니다.

@Module({
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

이처럼 NestJS에서 service는 Provider의 의존성 주입(Dependency Injection)을 통해 모듈화된 구조를 갖춰 코드의 유지보수성과 재사용성을 높이도록 만들어졌습니다.

참고 링크

Leave a Comment