NestJS는 효율적이고 확장 가능한 Node.js 서버 사이드 어플리케이션을 위한 프레임워크입니다. 최신의 자바스크립트를 사용하며 타입스크립트를 완벽히 지원합니다.
본질적으로 NestJS는 서버 사이드 어플리케이션을 빠르고 쉽게 작성할 수 있도록 지원하는 메소드와 구현 기능을 갖춘 노드 위의 계층입니다. NestJS는 여러분이 필요한 것을 모두 만족시켜주어 아주 편리합니다. 커스터마이징하기가 좋고 기본적으로 Express 기반에서 동작하지만 선택적으로 Fastify를 사용하게 설정할 수 있습니다.
Node.js가 있는데 NestJS를 써야 하는 이유는 무엇일까요?
Nest는 Node 위에서 추상화 계층을 제공하는데 이는 Node의 기능 뿐만 아니라 성능과 효율성을 높이기 위해 슈퍼차저 API를 활용할 수 있습니다.
개발자들은 기능을 사랑하고 여러분이 더 많은 기능을 가지고 있다면 그것은 무시하지 못할 장점입니다. 바로 Nest가 그런 경우입니다. 여러분의 개발 과정을 빠르게 해주는 여러 서드파티 모듈들을 사용할 수 있습니다.
백엔드 패러다임으로부터 완전히 벗어나지 않습니다. 동일한 종류의 코드를 쓰고 있음에도 견고성이 추가된 층을 가지고 있는 것입니다.
Nest는 데이터베이스와 함께 작업할 때 사용 가능한 ORM을 구성할 수 있씁니다. 즉, 쉽게 활용 가능한 Active Record 및 Data Mapper 패턴과 같은 좋은 TypeORM 기능을 제공합니다. Active Record 패턴은 단순함을 향상시키는 데 도움이 되고 Data Mapper 패턴은 유지보수 하기 좋은 코드를 만드는 데 도움이 됩니다.
또한 Nest의 아키텍처는 앵귤러 프레임워크로부터 많은 영감을 받았습니다. 필요할 때 쉽게 테스트할 수 있고 코드베이스를 효율적으로 유지하는 방법은 언제나 좋습니다. 그리고 Nest가 꼭 필요한 구조를 제공한다는 장점이 있습니다.
3티어 아키텍처 NestJS의 경향
튼튼한 구조를 만드는 것에 대해 얘기할 때, 우리가 가장 중요하게 생각하는 것은 어플리케이션의 여러 부분을 분리하여 함께 사용할 수 있도록 하는 것입니다. 구조적인 패턴을 따르는 것은 작성하고 있는 스파게티 코드를 해결하는 데 도움이 됩니다.
예를 들어 아래 플로우 다이어그램을 고려해볼 때 컨트롤러와 서비스 레이어가 함께 작동하여 논리를 수행하지만 둘은 완전히 다른 것입니다. 컨트롤러들은 본질적으로 어플리케이션의 루트(route)를 다룹니다. 하나의 컨트롤러는 몇 가지 다른 루트를 가지고 라우팅 메커니즘에 따라 어떤 컨트롤러가 어떤 요청에 대해 응답할지 달라집니다. 그러나 모든 비즈니스 로직을 컨트롤러 내부에 넣는다면 어떨까요? 아마도 아직 유저가 등록되지 않은 경우 새 유저를 등록하거나 컨트롤러 내에서만 유효성 검사를 수행할 수 있을 것입니다.
이러한 상황은 말이 되지 않습니다. 여러분의 어플리케이션 크키가 작다면 문제가 되지 않을 수 있습니다. 그러나 어플리케이션이 커짐에 따라 더 많은 컨트롤러와 루트가 필요해지며 더 많은 비즈니스 로직을 작성해야 합니다. 이렇게 된다면 상황은 통제 불가능해지며 유지보수할 수 없게 됩니다.
컨트롤러(controllers) : 컨트롤러의 유일한 목적은 어플리케이션에 대한 요청을 받고 route 처리를 하는 것입니다.
서비스 계층(service layer) : 비즈니스 로직을 포함합니다. 예를 들어 모든 CRUD 동작들이나 어떻게 데이터가 생성되고 저장되며 갱신되는지를 결정하는 메소드를 포함합니다.
데이터 접근 계층(data access layer) : 영구 스토리지에 저장된 데이터에 접근할 수 있는 로직을 제공합니다. ex. 몽구스와 같은 ODM
NestJS 프로젝트 디렉토리 구조
CLI를 사용해서 NestJS 프로젝트를 만들면, 몇 가지 보일러플레이트 파일을 제공합니다. 여러분들이 작업하는 코어 파일들입니다. 디렉토리 구조는 아래와 같습니다.
main.ts : 어플리케이션의 엔트리 파일로 모듈 번들을 가져와서 NestFactory를 사용하는 앱 인스턴스를 생성
여러분이 따라야 하는 특정 구조가 있다는 걸 알게 되었습니다. 이러한 구조는 깨끗하고 확장 가능하며 유지보수 가능한 코드를 작성하는 데 도움이 됩니다.
코드 살펴보기
서비스 파일을 생성하고 컨트롤러 파일 내에서 임포트하고 사용할 수 있는 몇 가지 함수를 구현하는 CatsService라는 클래스를 export 해봅시다.
import { Injectable } from '@nestjs/common';
@Injectable()
export class CatsService {
getAllCats(): string {
return 'Get all cats!';
}
getOneCat(): string {
return 'Get one cat!';
}
}
CatsService 클래스를 익스포트하고 세 가지의 메소드를 정의했습니다. 또한 @Injectable() 데코레이터를 사용했습니다. 데코레이터는 메타데이터를 첨부하고 주입 가능한 클래스를 종속성으로 나타냅니다. 클래스를 디펜던시로 주입했기 때문에 고양이 데이터를 반환하는 컨트롤러 내부에서 사용할 수 있습니다.
import { Controller, Get } from '@nestjs/common';
import { CatsService } from '../services/cats.service';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get('allcats')
getCats(): string {
return this.catsService.getAllCats();
}
@Get('onecat')
getOneCat(): string {
return this.catsService.getOneCat();
}
}
컨트롤러 파일에서 CatsService를 임포트하고 생성자 내에서 서비스 인스턴스를 생성합니다. CatsService 디펜던시는 클래스 생성자를 통해 주입됩니다. (dependency injection) CatsService 내에서 정의한 여러 메소드를 노출시킬 수 있습니다. 컨트롤러를 사용해서 고양이 데이터를 받아옵니다.
의존성은 클래스가 함수를 수행하는 데 필요한 서비스 또는 객체입니다. 의존성 주입(DI)은 클래스가 외부 소스로부터 종속성을 생성하는 대신 요청하는 디자인 패턴입니다.
@Get() 데코레이터는 인자를 받아 추가된 기능과 동일한 함수를 반환합니다. 또한 @Get() 데코레이터는 특정 route를 요청하는 데 사용할 수 있는 pathname을 허용합니다. 예를 들어 /cats/allCats 에 대한 요청은 getCats를 호출하여 모든 고양이를 반환합니다.
개요
본질적으로 NestJS는 서버 사이드 어플리케이션을 빠르고 쉽게 작성할 수 있도록 지원하는 메소드와 구현 기능을 갖춘 노드 위의 계층입니다. NestJS는 여러분이 필요한 것을 모두 만족시켜주어 아주 편리합니다. 커스터마이징하기가 좋고 기본적으로 Express 기반에서 동작하지만 선택적으로 Fastify를 사용하게 설정할 수 있습니다.
Node.js가 있는데 NestJS를 써야 하는 이유는 무엇일까요?
3티어 아키텍처 NestJS의 경향
튼튼한 구조를 만드는 것에 대해 얘기할 때, 우리가 가장 중요하게 생각하는 것은 어플리케이션의 여러 부분을 분리하여 함께 사용할 수 있도록 하는 것입니다. 구조적인 패턴을 따르는 것은 작성하고 있는 스파게티 코드를 해결하는 데 도움이 됩니다.
예를 들어 아래 플로우 다이어그램을 고려해볼 때 컨트롤러와 서비스 레이어가 함께 작동하여 논리를 수행하지만 둘은 완전히 다른 것입니다. 컨트롤러들은 본질적으로 어플리케이션의 루트(route)를 다룹니다. 하나의 컨트롤러는 몇 가지 다른 루트를 가지고 라우팅 메커니즘에 따라 어떤 컨트롤러가 어떤 요청에 대해 응답할지 달라집니다. 그러나 모든 비즈니스 로직을 컨트롤러 내부에 넣는다면 어떨까요? 아마도 아직 유저가 등록되지 않은 경우 새 유저를 등록하거나 컨트롤러 내에서만 유효성 검사를 수행할 수 있을 것입니다.
이러한 상황은 말이 되지 않습니다. 여러분의 어플리케이션 크키가 작다면 문제가 되지 않을 수 있습니다. 그러나 어플리케이션이 커짐에 따라 더 많은 컨트롤러와 루트가 필요해지며 더 많은 비즈니스 로직을 작성해야 합니다. 이렇게 된다면 상황은 통제 불가능해지며 유지보수할 수 없게 됩니다.
NestJS 프로젝트 디렉토리 구조
CLI를 사용해서 NestJS 프로젝트를 만들면, 몇 가지 보일러플레이트 파일을 제공합니다. 여러분들이 작업하는 코어 파일들입니다. 디렉토리 구조는 아래와 같습니다.
여러분이 따라야 하는 특정 구조가 있다는 걸 알게 되었습니다. 이러한 구조는 깨끗하고 확장 가능하며 유지보수 가능한 코드를 작성하는 데 도움이 됩니다.
코드 살펴보기
서비스 파일을 생성하고 컨트롤러 파일 내에서 임포트하고 사용할 수 있는 몇 가지 함수를 구현하는 CatsService라는 클래스를 export 해봅시다.
CatsService
클래스를 익스포트하고 세 가지의 메소드를 정의했습니다. 또한@Injectable()
데코레이터를 사용했습니다. 데코레이터는 메타데이터를 첨부하고 주입 가능한 클래스를 종속성으로 나타냅니다. 클래스를 디펜던시로 주입했기 때문에 고양이 데이터를 반환하는 컨트롤러 내부에서 사용할 수 있습니다.컨트롤러 파일에서 CatsService를 임포트하고 생성자 내에서 서비스 인스턴스를 생성합니다. CatsService 디펜던시는 클래스 생성자를 통해 주입됩니다. (dependency injection) CatsService 내에서 정의한 여러 메소드를 노출시킬 수 있습니다. 컨트롤러를 사용해서 고양이 데이터를 받아옵니다.
@Get() 데코레이터는 인자를 받아 추가된 기능과 동일한 함수를 반환합니다. 또한 @Get() 데코레이터는 특정 route를 요청하는 데 사용할 수 있는 pathname을 허용합니다. 예를 들어 /cats/allCats 에 대한 요청은 getCats를 호출하여 모든 고양이를 반환합니다.