NestJS는 Node.js의 유연함을 그대로 가지면서도 프레임워크 내에 유용한 기술을 이미 다수 구현해 두었습니다.
- NestJS는 Node.js에 기반을 둔 웹 API 프레임워크로 Express 혹은 fastify 프레임워크를 래핑하여 동작합니다. 아시다시피 Express와 fastify는 모두 Node.js를 쉽게 사용하기 위해 만들어진 프레임워크입니다. 즉, NestJS로 작성한 소스 코드를 Node.js 기반 프레임워크인 Express나 fastify에서 실행 가능한 자바스크립트 소스 코드로 컴파일하는 역할을 합니다.
- NestJS는 기본 설치 시 Express를 설치합니다. fastify와 같은 다른 프레임워크 대신에 Express를 사용하는 이유는 Express가 가장 널리 사용되고 있고 수많은 미들웨어가 NestJS와 호환되기 때문입니다.
- NestJS는 데이터베이스, 객체 관계 매핑(Object-Relational Mapping, ORM), 설정(Cofiguration) 및 유효성 검사 등 수많은 기능을 기본으로 제공합니다. 그러면서도 필요한 라이브러리를 쉽게 설치하여 기능을 확장할 수 있는 Node.js 만의 장점을 그대로 가지고 있습니다.
- NestJS는 앵귤러(Angular)로부터 영향을 많이 받았습니다. 모듈/컴포넌트 기반으로 프로그램을 작성함으로써 재사용성을 높입니다. 또 제어 반전(Inversion of Control, IoC), 의존성 주입(Dependency Injection, DI), 관점 지향 프로그래밍(Aspect-Oriented Programming, AOP) 와 같은 객체 지향 개념을 도입했습니다. 프로그래밍 언어는 타입스크립트(TypeScript)를 기본으로 채택하여 타입스크립트가 가진 타입 시스템의 장점을 누릴 수 있습니다.
Express vs. NestJS
Express | NestJS | |
개요 | 미니멀리스트 웹 프레임워크 | 자바스크립트의 최신 기능을 사용해 효율성을 추구하며 상업용 서버 응용프로그램 구축을 목표로 하는 프레임워크 |
라우터 | 직접 라우터 함수를 추가하거나, 미들웨어 사용 | @Controller() 데코레이터 사용 |
의존성 주입 | 없음 | 잘 만든 의존성 주입 기능을 제공함. 서비스의 의존 관계의 관리가 쉬움 |
에러 핸들링 | 직접 에러 처리를 해야 함 | @Catch() 데코레이터를 사용 |
테스트 | 직접 테스트 관련 도구들을 설치 및 실행해야 함 | jest를 기반으로 한 내장 테스트 모듈을 제공 |
인기도 | Node.js에서 가장 인기 있는 프레임워크 | 두 번째로 인기 있는 프레임워크 |
아키텍처 | 특정 아키텍처를 요구하지 않음 | 컨트롤러, 프로바이더, 모듈을 이용한 응용프로그램 아키텍처 제공 |
웹 프레임워크가 갖춰야 할 필수 기능은 다음과 같습니다.
- 최신 ECMA 스크립트 지원
- 타입스크립트
- CQRS(Command Query Responsibility Separation)
- HTTP 헤더 보안 (Express는 helmet 사용)
- 편리한 설정
- 인터셉터(Interceptor)
- 다양한 미들웨어(middleware)
- 스케쥴링
- 로깅
- 테스팅
- 스웨거(Swagger) 문서화
- ORM
NestJS는 이 중 대부분을 프레임워크에 내장하고 있고 내장하지 않은 기능 역시 쉽게 다른 모듈을 가져다 쓸 수 있습니다.
의존성 주입 (Dependency Injection, DI)
의존성 주입은 모듈 간의 결합도를 낮춰서 코드의 재사용을 용이하게 하여 모듈 내에서의 코드의 응집도는 포여서 모듈의 재사용을 꾀하고 모듈 간에는 결합도를 낮춰서 다양한 아키텍처에서 활용할 수 있게 해 줍니다. 이를 위한 장치들로 모듈, 가드, 파이프, 미들웨어, 인터셉터 같은 모듈과 코드의 의존 관계를 구성하는 프로그래밍 장치들이 있습니다.
데코레이터 (Decorator)
NestJS는 데코레이터를 많이 사용합니다. 데코레이터를 만드는 것은 까다롭지만 사용이 매우 직관적이고 간편하기 때문에 NestJS에서는 데코레이터를 적극적으로 사용하고 있습니다. 데코레이터를 잘 사용하면 횡단 관심사(cross-cutting concern)를 분리하여 관점 지향 프로그래밍을 적용한 코드를 작성할 수 있습니다. 데코레이터는 클래스(class), 메소드(method), 접근자(accessor), 프로퍼티(property) 및 매개변수(parameter)에 적용 가능합니다.
일반적으로 @함수명을 클래스나 함수의 윗 줄에 명시하고 적절한 매개변수를 추가하면 됩니다. 즉, @expression 형식으로 사용하며 expression은 데커레이팅된 선언(클래스, 메소드 등)에 대한 정보와 함께 런타임에 호출되는 함수여야 합니다.
HTTP 부분은 Express를 사용하기 때문에 아래 표와 같이 Express와 대응되는 데코레이터들이 모두 제공됩니다.
Decorator | Express |
Request(), Req() | req(Request object) |
Response(), Res() | res(Response object) |
Next() | next |
Session() | req.session |
Param(key?) | req.params, req.params[key] |
Body(key?) | req.body, req.body[key] |
Query(key?) | req.query, req.query[key] |
Headers(name?) | req.headers, req.headers[name] |
Ip() | req.ip |
HostParam() | req.hosts |
NestJS는 Express를 사용하기 때문에 Express 기반의 미들웨어를 대부분 사용할 수 있습니다. 정확하게는 HTTP 요청과 응답에 Express의 Request와 Response 객체를 기본으로 사용합니다.
다음 예는 유저 생성 요청의 본문을 데이터 전송 객체(Data Transfer Object, DTO)로 표현한 클래스입니다.
class CreateUserDto {
@IsEmail()
@MaxLength(60)
readonly email: string; // email: 이메일 형식(IsEmail) 문자열 & 길이는 최대 60자(MaxLength)
@IsString()
@Match(/^[A-Za-z\d!@#$%^&*()]{8,30}$/)
readonly password: string; // password: 문자열(IsString) & 정규표현식(Mathc)
}
데커레이터 종류별 특징은 다음과 같습니다.
데코레이터 | 역할 | 호출 시 전달되는 인수 | 선언 불가능한 위치 |
Class decorator | 클래스의 정의를 읽거나 수정 | constructor | d.ts file, declare class |
Method decorator | 메서드의 정의를 읽거나 수정 | target, propertyKey, propertyDescriptor |
d.ts file, declare class, overload method |
Accessor decorator | 접근자의 정의를 읽거나 수정 | target, propertyKey, propertyDescriptor |
d.ts file, declare class |
Property decorator | 속성의 정의를 읽음 | target, propertyKey | d.ts file, declare class |
Parameter decorator | 매개변수의 정의를 읽음 | target, propertyKey, parameterIndex |
d.ts file, declare class |
참고 사이트
- NestJS로 배우는 백엔드 프로그래밍 - 한용재
- 우형의 새로운 백엔드 개발 표준 - WOOWACON2023