NestJs, NodeJs, Typescript

Kim sejin·2023년 11월 14일

NestJs

목록 보기
3/4
post-thumbnail

Hello NestJs

Nestjs는 NodeJs를 기반에 둔 웹 API 프레임워크이다. 이것은 Express 또는 Fastify 프레임워크를 래핑하여 동작한다. 하지만 기본으로 Fastify를 사용하지 않고 가장 널리 사용되고 있는 Express가 사용되고 있다.


Node vs Nest

NodeJs는 손쉽게 사용할 수 있지만 과도한 유연함으로 인해 알맞은 라이브러리를 찾기 위해 많은 시간을 할애하여야 한다. 이에 반해 Nestjs에서는 모듈/컴포넌트 기반으로 프로그램을 작성함으로써 재사용성을 높인다. 또한 객체 지향 개념을 도입하였다.

구분ExpressNestJs
유연함/확장성가벼운 테스트용 서버를 띄울 수 있음. 자유도가 높은만큼 맞는 라이브러리를 찾기 위해 수고가 필요함미들웨어, IoC, CQRS 등 많은 기능이 포함 원하는 기능이 없다면 다른 라이브러리를 적용하여 사용 가능
타입스크립트 지원추가설정을 통해 사용 가능기본으로 내장되어있음
커뮤니티가장 큼꾸준히 증가 중

NestJs 프로젝트 생성

npm i -g @nestjs/cli - 패키지 설치
nest new project-name - 프로젝트 생성
npm run start:dev - 프로젝트 실행


단순한 서비스를 개발할 때 부가적으로 해야할 일

  1. 환경변수 설정 - 개발자의 로컬 개발 환경, 배포 하기 전 테스트용 서버에 배포하는 스테이지 환경, 실제 운영하는 프로덕션 환경으로 구성할 수 있어야한다.
  1. 요청 유효성 검사 - 프론트엔드에서 들어오는 요청이 잘못된 값이 전달된 경우라면 400 Bad Request로 응답해야한다.

  2. 인증 - 사용자의 리소스에 접근하기 위해서 권한이 필요하고 로그인 과정을 거쳐야 한다. 토큰 방식에서는 주로 JWT를 사용한다.

  3. 로깅 - 서버의 상태가 양호한지 주기적으로 검사해야한다. 상태가 좋지 않다면 경고를 발생시켜야 한다.

  4. CQRS - 복잡한 코드가 생기는 경우가 있기에 데이터베이스에 변형을 가하는 명령과 데이터 읽기 요청을 처리하는 조회 로직을 분리함으로써 성능, 확장성을 강화할 수 있다.

  5. 클린 아키텍처 : 클린 아키텍처는 SW의 계층을 분리하고 저수준의 계층이 고수준의 계층에 의존하도록 한다.

  6. 단위 테스트 : 단위 테스트는 개발자가 테스트 코드를 이용하여 수행하는 최소 단위 테스트 기법이다.


웹 개발 기초 지식

웹 프레임워크

예전의 웹페이지에서 구동되는 애플리케이션은 모두 SSR(server-side rendering) 방식으로 동작했다. 이 방식은 서버가 요청을 처리한 다음 HTML과 자바스크립트 응답을 브라우저에 전송하면 브라우저는 서버로부터 전달되는 HTML 코드를 화면에 뿌려주기만 하면 됐었다.

리액트가 큰 인기를 얻으면서 SPA 기반으로 구축된 서비스가 늘어났다. 이 방식은 서버로부터 매 요청에 대한 최소한의 데이터만 응답으로 받고 화면 구성 로직을 프론트에서 처리한다.

시간이 지날수록 웹 기술은 점점 발전했고, 자연스럽게 개발에 필수적인 요소들을 묶어 쉽게 쓸 수 있고자 하는 시도가 생겨났다 = 웹 프레임워크


웹 프레임워크가 갖춰야할 필수 기능

  1. 최신 ECMA 스크립트 지원
  2. 타입스크립트(typescript)
  3. CQRS(command query responsibility separation)
  4. 편리한 설정(setting)
  5. 인터셉터(interceptor)
  6. 다양한 미들웨어(middleware)
  7. 스케줄링
  8. 로깅(logging)
  9. 테스팅(testing)
  10. 스웨거 문서화(swagger)
  11. ORM

NodeJs

자바스크립트는 이전까지 프론트엔드에서 사용하는 언어라는 인식이 강하였고, 실제 script 태그를 주로 삽입하여 사용하였다. 하지만 이것은 보안에 취약하다는 문제점이 있었다. 하지만 Nodejs 등장으로 인해 자바스크립트를 이용하여 서버를 구동할 수 있게 되었다.

따라서 프론트엔드와 백엔드에서 같은 언어를 사용한다는 것은 큰 장점이다.


단일 스레드에서 구동되는 non-blocking I/O 이벤트 기반 비동기 방식

멀티스레딩

여러 작업 요청이 한꺼번에 들어올 때, 각 작업을 처리하기 위한 스레드를 만들고 할당하는 방식을 멀티스레딩이라고 한다. 이 방식은 동시에 여러 작업을 수행하므로 속도는 빠르지만 잘못 작성하게 된다면 락에 빠질 수 있다. 스레드가 늘어날수록 메모리를 소비하게 된다.

단일스레드

이에 비해 Nodejs는 하나의 스레드에서 작업을 처리한다. 앞의 작업이 끝날 때까지 기다리지 않고(non-blocking 방식) 비동기로 처리한다. 입력은 하나의 스레드에서 받지만 순서대로가 아닌 먼저 처리된 결과를 반환하므로 단일 스레드 non-blocking 이벤트 기반 비동기 방식이다.


장단점

장점

  1. 단일스레드 방식은 서버의 자원에 크게 부하를 가하지 않는다. 그렇기에 대규모 네트워크 애플리케이션을 개발하기에 적합하다.
  2. 하나의 스레드로 동작하는 것처럼 코드를 작성할 수 있다.

단점

  1. 멀티스레딩을 직접 만들고 관리하다 교착 상태에 빠질 수 있다.
  2. 컴파일러 언어의 처리 속도에 비해 성능이 떨어진다.
  3. 여러 이벤트를 동시에 처리하는 경우 콜백 지옥에 빠지는 경우가 있다.

이벤트 루프

이벤트 루프는 시스템 커널에서 가능한 작업이 있다면 그 작업을 터널에 관할한다. NodeJs가 단일 스레드이지만 non-blocking 작업을 할 수 있는 핵심 기능이다.

이 부분은 다음에 포스팅으로 자세하게 다룰 예정


패키지 의존성 관리

package.json의 역할
1. 애플리케이션이 필요로 하는 패키지 목록을 나열한다.
2. 시맨틱 버저닝 규칙으로 필요한 버전을 기술한다.
3. 다른 개발자와 같은 빌드를 구성할 수 있다.


package-lock.json의 역할
1. node_modules나 package.json 파일의 내용이 바뀌면 npm install 명령을 수행할 때 자동 수정된다.
2. package.json에 선언된 패키지들이 설치될 때 정확한 버전과 서로 간의 의존성을 표현한다 => 팀원들 간에 정확한 개발 환경 공유가능
ex) package-lock.json이 이미 존재한다면 npm install시 이 파일을 기준으로 패키지를 설치

Typescript

자바스크립트 코드에 타입 시스템을 도입하여 런타임에 에러가 발생할 가능성이 있는 코드를 분석하여 런타임에 발생할 오류를 미리 컴파일 타임에 잡아준다.


변수 선언

[선언 키워드][변수명]: [타입]

const - 선언 후 재할당이 불가능
let, var - 재할당이 가능하며 값을 바꿀 수 있다.

let과 var의 차이는 호이스팅 여부이다.

  • var는 변수를 사용한 후에 선언이 가능하다.

타입스크립트에서 지원하는 타입

객체 타입

: 객체 타입은 속성을 가지고 있는 데이터 컬렉션이다.

함수 타입

: 자바스크립트는 함수를 변수에 할당하거나 다른 함수의 인수로 전달할 수 있다. 함수의 결과로 반환가능하다. 함수 func의 타입을 검사하면 function이 나온다(일급 함수라고 함)

any/unknown/never

any - 어떠한 타입의 값도 받을 수 있는 타입
unknown - 어떤 타입도 할당 가능하지만 다른 변수에 할당 또는 사용할 때 타입을 강제 -> any가 일으키는 오류를 줄임
never - 이 타입의 변수에는 어떤 값도 할당할 수 없다. 함수의 리턴 타입으로 지정하면 함수가 어떤 값도 반환하지 않는다.


타입 정의하기

타입스크립트는 타입을 정의해서 사용한다. 변수에 객체를 바로 할당하지 않고 interface로 선언할 수 있다. 인터페이스를 이용하여 User의 타입을 정의하는 것이다.

// 인터페이스
interface User{
	name: string;
    age: number;
}

const user: User = {
	name: 'Dexter',
    age: 21,
}

// 클래스로 선언
class User{
  constructor(name: string, age: number){}
}

const user: User = new User('Dexter', 21);


타입 구성하기

자바스크립트 변수에 어떠한 타입의 값도 할당할 수 있다. 이러한 개념duck typing(덕타이핑)이라 부른다. 여러 타입을 조합한 새로운 타입을 가지는 것이다.

유니언 타입

여러 타입을 조합한 타입이다. 한 변수가 string 또는 string[] 타입을 가질 수 있다.

이 유니언 타입을 활용하면 변수가 가질 수 있는 값을 제한할 수 있다.

type Status = "Ready" | "Waiting";

// 위의 코드를 열거형으로 사용
enum Status {
	READY = 'Ready',
    WAITING = 'Waiting",
}

enum 참고 자료


제네릭 타입

어떤 타입이든 정의될 수 있지만 호출되는 시점에 타입이 결정된다.

function identity(arg: any): any{
	return arg
}

함수의 반환값이 any로 되어 있기 때문에 'test'를 인수로 전달 경우에 전달한 인수의 string 타입이 반환 시 any가 되어버린다. 반면에 제네릭 타입을 사용하게 되면 리턴이 되는 타입은 함수를 호출하는 시점의 인수로 넣은 타입으로 결정되게 된다.


// 보통 제네릭 선언시 대문자 한글자를 사용한다.
function identity<T>(arg: T): T{
	return arg;
}

출처

이 포스팅은 NestJs로 배우는 백엔드 프로그래밍 - 한용재 님의 책을 바탕으로 작성되었습니다.

1개의 댓글

comment-user-thumbnail
2023년 11월 14일

정보 감사합니다.

답글 달기