고양이가 귀여운 NestJS 찍먹

Hoon·2022년 7월 22일
0

[NestJS]

목록 보기
1/1
post-thumbnail

Prologue

SOPT에서의 세번째 서버 파트여서 때문인지 Node.js 진영에서 가장 많이 사용되고 SOPT 내에서도 배우고 활용하는 express 이외에 다른 프레임워크를 사용해보고 싶었다.

Spring이나 Django 같은 구조적으로 튼튼한 프레임워크에 반해 Node.js 기반에서는 그런 부분이 부족했는데 마침 견고한 프레임워크로 등장한 친구가 NestJS다!

Express를 사용해 여러 프로젝트를 하면서, Express는 뭔가 코드들을 모듈화해서 너무 자유롭게 막 갖다 붙이는 레고 느낌이 들었었던터라 NestJS가 더욱 매력적으로 느껴졌다.

그렇게 이번 소비 순간의 감정에 집중하는 나를 위한 소비기록, POME에서 NestJS 기반의 서버를 구축하기로 했다!

NestJs

NestJs는 SOPT 30기 서버 파트에서 배운 Express와 같은 서버 프레임워크다. 굉장히 쉽게 서버를 개발할 수 있게끔 도와주는 Express와는 다르게 서버 시스템의 전반적인 디자인을 지원해주는 친구가 바로 NestJS이다.

그래서 OOP(객체지향), DI(의존성 주입) 등등의 디자인 패턴을 적용해볼 수 있다.
NestJS의 철학이나 더 자세한 설명은 공식문서 또는 잘 정리되어 있는 사이트를 참고해보는 것이 좋을 듯 하다.

NestJS의 기본 구조


출처. kimjeongwonn.log 감사합니다.

NestJS는 Service(Provider), Controller를 하나의 알맹이(Module)로 묶고, 묶은 알맹이(Module)들을 최상위 모듈인 app.module.ts 에 주입하는 방식으로 설계된다.

새로 보는 것들은 직접 해보면 가장 재밌게 이해할 수 있다! 실제로 알맹이가 어떻게 생겨나는지 알아보자.

yarn global add @nestjs/cli

위의 명령어를 통해 @nestjs/cli를 설치하고,

nest new hello

본인의 작업 디렉토리에 위의 명령어를 입력하면 앞서본 기본 구조를 쉽게 살펴볼 수 있다.

src
 | main.ts                    
 | app.module.ts              
 | app.controller.ts          
 | app.service.ts            

보시다시피 기본 구조는 이러하다. 여기에 각자 이상적인 디렉토리 구조를 설계하는 것도 좋고, 우리들의 친구 깃허브를 통해 NestJS Server 관련 레포지토리를 확인해 설계하는 것도 좋다.

앱잼팀 POME에서는 요기를 참고하여 디렉토리 구조를 설계/구축했다.

그럼, Service, Controller, Module을 찍먹해보자.

Controller

Controller는 서버 파트 세미나를 진행했다면 잘 알고 있을 것이라고 생각한다. NestJs에서도 똑같은 역할을 하는 친구이다.

공식문서에서 제공하는 Controller 예시를 보자. 놀랍게도 귀여운 고양이를 가지고 노는 CRUD 예제이다.

@Controller('cats')
export class CatsController {
  @Post()
  create(@Body() createCatDto: CreateCatDto) {
    return 'This action adds a new cat';
  }

  @Get()
  findAll(@Query() query: ListAllEntities) {
    return `This action returns all cats (limit: ${query.limit} items)`;
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return `This action returns a #${id} cat`;
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
    return `This action updates a #${id} cat`;
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return `This action removes a #${id} cat`;
  }
}

CatsController라는 이름의 클래스 안에 CRUD를 형성하는 메서드들을 구현하고, 그 위에 @Post 처럼 이메일에 붙는 골뱅이 같은 친구를 붙이면 컨트롤러가 짠하고 완성된다! 정말 그게 끝이다. 골뱅이같은 친구는 데코레이터라고 부르고, Spring에서 사용하는 어노테이션 같은 역할을 해준다!

Provider(Service)

다음은 서비스 로직을 담당하는 Provider(Service)이다. 서버 파트를 수료했다면 컨트롤러 내부에서 비즈니스 로직을 수행하는 것을 지양하고 비즈니스 로직만을 담당하여 역할 분리를 확실히 해야한다는 점을 알고 있을 것이다. NestJS에서도 마찬가지이다.

비즈니스 로직을 수행하는 Provider를 만들고, 앞서 만든 Controller에 주입하여 사용한다.
그럼 NestJS 공식문서에서 제공하는 예제를 확인해보자!

@Injectable()
export class CatsService {
  private readonly cats: Cat[] = [];

  create(cat: Cat) {
    this.cats.push(cat);
  }

  findAll(): Cat[] {
    return this.cats;
  }
}

서비스도 컨트롤러와 마찬가지로 CatsService라는 이름의 클래스를 만든다. 그리고 그 안에 원하는 로직을 수행하는 메서드들을 구현한다!

주목할 점은, @Injectable()라는 데코레이터를 붙였다는 점이다. @Injectable()은 해당 클래스가 언제든지 어디에나 주입이 가능하다는 것을 알려주는 일종의 표지판으로 보면 편하다. 주입이 가능한 클래스에 대해 데코레이터를 통해 Inject가 가능함을 선언하는 것이다!

고양이 서비스 주입!

그럼 이제, 고양이를 가지고 놀 수 있는 컨트롤러와 프로바이더(서비스)가 준비됐다. 컨트롤러에 방금 만든 서비스를 주입하여 코드를 멋지게 만들어보자.

아래 코드 역시 NestJS 공식문서에서 제공하고 있다.

import { CatsService } from './cats.service';

@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();
  }
}

CatsServiceimport하여 CatsContoller에 주입을 하고 있는 모습이다. 이제 고양이 컨트롤러는 class constructor를 통해 서비스를 주입하였고 컨트롤러 내부에서 this 키워드를 통해 로직을 수행할 수 있다!

그럼 알맹이(Module)는?

알맹이(Module)는 앞서 만든 컨트롤러와 프로바이더를 하나로 감싸주는 비닐 봉다리 같은 느낌이다.

이해가 잘 가지 않는다면 아래의 코드를 보자

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

@Module이라는 데코레이터 안에 controllers에 CatsController, providers에 CatsService를 배열 형태로 제공하면 하나의 알맹이, 모듈이 완성된다!

이제 이 모듈은 귀여운 고양이와 관련된 프로바이더들과 하나의 고양이 컨트롤러를 함께 묶어두게 된다.

그리고 이 모듈을 최상위 모듈인 app.module.ts에 주입하면 고양이 API가 준비된다!

import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule {}

final

그럼 최종적으로는 아래와 같은 구조를 가지게 된다.

src
- cats
- - interfaces
- - - cat.interface.ts
- - cats.controller.ts
- - cats.module.ts
- - cats.service.ts
-app.module.ts
-main.ts

이번 앱잼에서 NestJS를 활용해보며, Express를 경험해본 개발자라면 한번쯤 사용해보면 좋을 프레임워크라고 생각하여 찍먹정도로 정리해보았다. 깊은 내용이 아니라 NestJS만의 온전한 매력을 다 보여주지 못한 것 같지만, 작은 흥미라도 생겼다면 지금 바로 NestJS 기반의 서버를 구축해보는 것을 강력 추천한다!

NestJS + Prisma 기반으로 구축한 POME 서버가 궁금하다면
포미 레포지토리를 방문해보..

profile
Being Back-end Developer

0개의 댓글