NestJS 시작하기
nestJS - cli 설치
사전 조건 : node lts버전 설치
|
|
또는
|
|
이렇게 package.json 파일에서 정상적으로 설치되었음을 확인할 수 있다.
nestJS - new Project 시작하기
|
|
위와 같이 입력하면 현재 터미널이 위치한 폴더 내에 새로운 “nestjs-test"폴더가 만들어지면서 그 안에 세팅이 된다.
만약 $ mkdir nestjs-test
로 폴더를 만들고 이 위치에서 진행중이라면,
|
|
위와 같이 입력시 현재 폴더명 그대로 새로운 프로젝트가 진행된다.
계속해서 진행시 아래와 같은 선택을 묻는다.
npm 또는 yarn 등, 편한 패키지로 선택하면
nestJS 기본 세팅이 이루어진다.
위 이미지와 같이 prettier부터 controller-service-model, main.ts, jest 등 기본적인 구성이 모두 세팅된다. (시간이 조금 걸릴 수 있다.)
모듈 생성
nestJS에서는 nest 명령어로 모듈을 생성할 수 있다.
|
|
설명
nest : nest cli 사용 g : generate module : schematic that I want to create boards : name of schematic
controller, service 생성하기
|
|
한줄씩 차례로 입력하면 된다.
설명
nest : using nest cli g : generate controller : controller schematic service : service schematic boards: name of the schematic –no-spec: 테스트를 위한 소스코드 생성을 하지 않겠다!
Tip
접근제한자를 이용해서 소스 간단하게하기 접근제한자(public,protected,private)을 생성자(constructor) 파라미터에 선언하면 접근제한자가 사용된 생성자파라미터는 암묵적으로 클래스 프로퍼티로 선언된다.
NestJS에서 request의 body값은 어떻게 가져올까?
NodeJS에서는 req.body
로 가져올 수 있다.
|
|
하지만 NestJS에서는 @Body body
를 이용해서 가져온다.
이렇게 하면 모든 request에서 보내온 값을 가져올 수 있으며,
만약, 하나씩 가져오려면
@Body('title') title
혹은
@Body('description') description
이런식으로 가져올 수 있다.
|
|
NestJS에서 Param은 어떻게 가져올까?
localhost:3000/:id 와 같은 params 값의 경우, body와 유사하다.
위의 경우에는 findOne(@Param('id') id: string)
과 같이 가져오면 된다.
만약 여러개의 Param을 가져와야 한다면,
findOne(@Param() params: string[])
으로 가져올 수 있다.
타입스크립트의 데코레이터는 파이썬의 데코레이터나 자바의 어노테이션과 유사한 기능을 한다.
클래스, 메서드, 접근자, 프로퍼티, 매개변수에 적용 가능
참고 - 2.6 데코레이터 - NestJS로 배우는 백엔드 프로그래밍
DTO (Data Transfer Object)란?
계층간 데이터 교환을 위한 객체
DB에서 데이터를 얻어 Service나 Controller 등으로 보낼 때 사용하는 객체를 말한다.
DTO는 데이터가 네트워크를 통해 전송되는 방법을 정의하는 객체이다.
NestJS 공식문서에서는 interface보다는 class를 이용해서 정의하는 것을 추천하고 있다.
DTO(Data Transfer Object)를 쓰는 이유는?
- 데이터 유효성을 체크하는데 효율적
- 더 안정적인 코드로 만들어준다. 타입스크립트의 타입으로도 사용된다.
예시) controller, service에서 인자로 title, description이 있는 상황에서 만약 title을 다른 인자로 바꾼다면?
- 인자가 하나인 경우에는 크게 문제가 없겠지만 이것들이 여러개라면 모든 파일에서 인자를 다 수정해줘야 한다.
- 하지만 DTO를 이용한다면 이 모든 것을 하나의 class로 처리하고 해당 class만 수정하면 된다.
Pipe란??
파이프는 @Injectable() 데코레이터로 주석이 달린 클래스이다.
파이프는 data transformation (데이터 변형)과 data validation (데이터 유효성)을 위해서 사용된다.
파이프는 컨트롤러 경로 처리기에 의해 처리되는 인수에 대해 작동한다.
Nest는 메소드가 호출되기 직전에 파이프를 삽입하고 파이트는 메소드로 향하는 인수를 수신하고 이에 대해 작동한다.
Data Transformation?
입력 데이터를 원하는 형식으로 변환 (예 : 문자열을 정수로)
PIPE 사용하는 법 (Binding Pipes)
- Handler-level Pipes
- Parameter-level pipes
- Golbal-level Pipes
Built-in PIpes
NestJS에서 기본적으로 사용할 수 있는 6가지 파이프
- ValidationPipe
- ParseIntPipe
- ParseBoolPipe
- ParseArrayPipe
- ParseUUIDPipe
- DefaultValuesPipe
파이프를 이용한 유효성 체크 검사
필요한 모듈
- class-validator, class-transformer
npm install class-validator class-transformer --save
- Documentation page
예시
create-board.dto.ts 파일에서
|
|
먼저 위와 같이 각 인자별로 반드시 있어야 하는 곳에 @IsNotEmpty
를 적용시킨다.
controller 파일에서
|
|
다음으로 위와 같이 해당 부분에 @UsePipes(ValidationPipe)
를 적용시킨다.
위 방법은 앞서 언급했던 3가지 Binding Pipes 중, Handler-level Pipes이다.
@IsNotEmpty를 적용하지 않았을 경우 실제 Postman을 돌려보면 UsePipes에서 해당 함수를 찾을 수 없다는 오류가 뜨며, @UsePipes를 적용하지 않았을 경우에는 해당 유효성 검사 자체가 이루어지지 않는다.
에러를 표출해주기 위해서는
예를 들어 찾는 게시물이 없는 경우, 예외 인스턴스를 생성해서 이용할 수 있다.
|
|
NotFoundException
은 nestjs에 있는 인스턴스이다. (import로 사용가능)
사용시 다음과 같은 에러메세지를 볼 수 있다.
|
|
여기서 만약 에러메세지를 따로 넣어주고 싶다면,
|
|
이렇게 하면, 아래와 같이 response 된다.
|
|
커스텀 파이프 구현방법
먼저 Pipe Transform이란 인터페이스를 새롭게 만들 커스텀 파이프에 구현해줘야 한다.
이 Pipe Transform 인터페이스는 모든 파이프에서 구현해줘야 하는 인터페이스이다.
그리고 이것과 함께 모든 파이프는 transform()메소드를 필요로 한다.
이 메소드는 NestJS가 인자(arjuments)를 처리하기 위해서 사용된다.
|
|
transform() 메소드
이 메소드는 2 개의 파라미터를 가진다.
- 첫번째 파라미터는 처리가 된 인자의 값(value)이며,
- 두번째 파라미터는 인자에 대한 메타 데이터를 포함한 객체이다.
transform()메소드에서 return된 값은 Route 핸들러로 전해진다.
만약 예외(Exception)가 발생하면 클라이언트에 바로 전해진다.
mySQL 및 TypeORM
설치
- typeorm
- mysql
- @nestjs/typeorm
이렇게 3가지 모듈을 설치한다.
|
|
참고문서 documentation
설정
src 폴더 아래 configs 폴더 생성 후 그 안에 typeorm.config.ts
파일 생성
DAO단 분리
기존 내가 알던 model폴더에서 000.dao.ts 라고 파일명을 붙였던 것과 달리,
소스 강의에서는 000.repository.ts 파일명을 사용하고 있다. 그 외에는 동일하다.
게시물 삭제
remove()? vs delete()?
- remove
- 무조건 존재하는 아이템을 remove 메소드를 이용해서 지워야 한다. 그렇지 않으면 에러 발생(404 error)
- delete
- 만약 아이템이 존재하면 지우고 존재하지 않으면 아무런 영향이 없다.
- 이러한 차이로 remove를 이용하면 하나의 아이템을 지울 때 두번 데이터베이스를 이용해야 하기 때문에 (아이템 유무 + 지우기) 소스강의에서는 데이터베이스에 한번만 접근해도 되는 delete 메소드를 사용한다.
Error Handling
에러를 잡아내고 싶다면 우선,
|
|
를 이용하여 에러를 확인할 수 있다.
http에서 해당 API를 돌려보면, 아래와 같은 로그를 터미널에서 확인할 수 있다.
|
|
해당 error code 확인 후,
다시 아래와 같은 방식으로 수정하면 정상적으로 잡고자 하는 에러를 잡아낼 수 있다.
|
|
코드 수정 후, http Request 실행시
|
|
statusCode 409부터 정상적으로 송출하고자 하는 에러 메세지까지 모두 이상없음을 확인가능하다.
인증 및 인가 - bycriptjs
hashedPassword 생성 및 검증
우선 인증 인가 부분에 필요한 bcrypt를 설치한다.
|
|
import
는 다음과 같다.
|
|
회원가입시, bcrypt로 hashedPassword 생성
|
|
로그인시, hashedPassword를 비교하여 검증 ( bcrypt.compare
)
|
|
jwt token 생성
필요 모듈
- @nestjs/jwt : nestjs에서 jwt를 사용하기 위해 필요한 모듈
- @nestjs/passport : JWT를 이용하여 인증 처리하는 등의 과정을 훨씬 쉽게 만들어주는 모듈
|
|
위 터미널 명령어와 같이 총 4개의 모듈을 설치한다.
- @nestjs/jwt
- @nestjs/passport
- passport
- passport-jwt
passport 사용
Passport 모듈이란?
토큰이 유효한 토큰인지 서버에서 secret text를 이용해서 알아내면 payload 안에 유저 이름을 이용해서,
데이터베이스 안에 있는 유저 이름에 해당하는 유저 정보를 모두 가져올 수 있다.
이러한 처리를 쉽게 해주는게 Passport 모듈이다.
–> 쉽게 말해 로그인 이후, 토큰 확인 과정을 말한다!!!
|
|
nestJS의 미들웨어
- Pipes : 파이프는 요청 유효성 검사 및 페이로드 변환을 위해 만들어진다. 데이터를 예상한 대로 직렬화 한다.
- Filters : 필터는 오류 처리 미들웨어이다. 특정 오류 처리기를 사용할 경로와 각 경로 주변의 복잡성을 관리하는 방법을 알 수 있다.
- Guards : 가드는 인증 미들웨어. 지정된 경로로 통과할 수 있는 사람과 허용되지 않는 사람을 서버에 알려준다.
- Interceptors : 인터셉터는 응답 매핑 및 캐시 관리와 함께 요청 로깅과 같은 전후 미들웨어. 각 요청 전후에 이를 실행하는 기능은 매우 강력하고 유용하다.
각각의 미들웨어가 불러지는(called) 순서
|
|
UseGuards
UseGuards 안에 @nestjs/passport에서 가져온 AuthGuard()를 이용하면 요청안에 유저 정보를 넣어준 수 있다.
|
|
UseGuards가 아닌 바로 객체에 접근하려면?
커스텀 데코레이터를 생성하여 접근할 수 있다.
|
|
위 예시는, UseGuards를 사용하고 그 안에 있는 정보를 사용하는 방법이기에 UseGuards가 필요하다.
인증된 유저만 게시물을 사용할 수 있게 하기
우선 auth 모듈의 인증인가 부분을 boards 모듈에서도 사용할 수 있게 한다.
|
|
컨트롤러 boards 아래 넣게되면 미들웨어처럼 작동하여,
모든 boards API는 토큰을 필요로 하게 된다.
유저와 게시물 데이터의 관계 형성
사용자 1명은 여러개의 게시물을 작성할 수 있다.
때문에 OneToMany Relationship, ManyToOne Relationship의 성격을 동시에 가지는데,
User Entity, Board Entity에서 각각 설정할 수 있다.
|
|
Log
로그의 종류
- Log - 중요한 정보의 범용 로깅
- Warning - 치명적이거나 파괴적이지 않은 처리되지 않은 문제
- Error - 치명적이거나 파괴적인 처리되지 않은 문제
- Debug - 개발자용 / 오류 발생시 로직을 디버그하는 데 도움이되는 유용한 정보입니다.
- Verbose - 응용자용 / 응용 프로그램의 동작에 대한 통찰력을 제공하는 정보입니다.
예시
|
|
|
|
설정
.env
파일 사용 관련
필요 모듈 설치
|
|
Related Content
- Swagger를 이용한 백엔드의 효과적인 API명세 전달
- 백엔드 - Typescript-Express 환경에서 Jest 및 Node 환경에 따라 Dotenv 설정 분리
- Error Log - Jest.spyOn()에서 재사용함수에 대한 모의 불가
- Webina 참여 회고 - 원티드 주최 'ChatGPT 시대에 구성원의 역량을 어떻게 육성할 것인가?'
- AWS EC2에서 Product 서버와 개발용 서버 같이 사용하기