이미 nestcli
를 설치했기 때문에, 터미널에서 g 키워드(generate
)만을 가지고 필요한 것들을 생성해낼 수 있다.
nest g co
nest g s
nest g mo
이런식으로, Controller
를 생성함과 동시에, app.module.ts
는 자동으로 파일을 import
해 오며,
해당 ts
파일이 들어갈 디렉토리를 생성한다.
또 동시에 movies.controller.spec.ts
파일도 자동으로 생성된다.
NestJS에서
spec
파일은 무엇인가요?
유닛테스트를 진행할 수 있는 테스트 파일!
이제 생성된 Controller
내부에 대략적인 리턴될 메세지를 적어주자.
아직 Service
에서 로직을 작성하지 않았기 때문에, 그냥 Controller
에서 바로 리턴보내는 것으로 하자.
구조적인 문제나 사소한 오타 문제가 없다면
주소창에서 localhost:포트번호/movies
라고 쳤을 떼 정상적으로 표출이 될 것!
경로 설정해준 부분 -> 라우터
각 HTML 메서드 -> expression 어플리케이션에서의 라우터들
url에 있는 아이디를 얻고 싶다면? 무언가가 필요하면 우리가 요청해아한다.
앞서 RESTful한 개발에서 사용했던 path parameter!를 생각해보면
localhost:포트번호/movies/3
👉🏻 parameter를 요청하는 것!
👆🏻 "id라는 paramater
를 id라는 argument
에 string
타입으로 저장" 이라는 뜻
path parameter
로 받을 값과param
으로 가져오는 값은 같게 명시해주어야 하지만,
string 타입
으로 받고싶은 값은 마음대로 명명할 수 있다.
controller에서 사용되는 HTML 메서드들을 알아보자
Get
,Post
,Delete
,Put
,Update
Put
- 모든 리소스를 업데이트한다.
Patch
- 리소스의 일부분만 업데이트한다. (
path parameter
로 요청)
단순히 URL에 parameters
만 추가해서 보내는 것 말고도, request
를 보낼 때 body
에 다른 값들을 담아서 보내보고 싶다면?
👉🏻 @Body
를 사용하면 된다.
👉🏻 해당 데코레이터를 통해 movieData
안의 request
의 Body
를 가져오기 위한 것!
이러한 개념은 Patch
메서드를 사용할 때 사용된다.
Patch
는 일부분만 업데이트되기 때문에, 업데이트 할 대상을 특정지을 parameter
를 꼭 받아와야한다.
요로케 입력받을 값들을 데코레이터를 활용해서 명시해두고,
Spread
연산자를 활용해서 리턴값을 적어주면 다음과 같은 리턴값을 확인할 수 있다. 👇🏻
검색 등의 기능을 구현할 때를 감안해서 Query String을 입력받는 경우를 생각해보자.
이런 검색조건을 걸고싶은 경우를 살펴보자.
localhost:포트번호/search?year=2000
/search
라는 경로를 가지는 함수보다:id
라는 파라미터를 받는 함수가 먼저 나와있는 경우,
Get
데코레이터로 된pathParameter
를 받는 함수가 먼저 나와있으면
그 이후의 함수들이 작동하지 않는다고 한다 헐
(NestJS, express.js를 사용하면 겪는 일이라고 한다.)
그렇기 때문에 요로케, 순서를 잘 신경써서 작성해줘야 한다는 것!
path parameter
를@Param
데코레이터로 받은 것처럼,query string
은@Query
데코레이터로 받아주어야 한다.
Single-responsibility principle
- 하나의 module, class, function이 하나의 기능은 꼭 책임져야 한다!
Controller
가 url 매핑, request
받기, Query
,Param
,Body
넘기기, 등의 작업을 한다면
Service
는 로직을 작성하고 관리한다.
우리가 작업하는 디렉토리 내에 새로운 폴더를 생성하고, 데이터베이스를 사용한다고 가정하기 위해 가짜 데이터 파일을 생성한다.
👉🏻👉🏻JS에서 export, import란 무엇일까?
함수명 옆에 어떠한 값을 리턴해줄 지를 명시해주고
return
부분에 실제 리턴값을 적어준다.
getOne 함수의 경우, string 타입
의 id
라는 값을 받고, Movie 객체
를 리턴해주는데
리턴해주는 이 값은 앞서 선언해둔 movies 데이터 파일
에서 movie.id
가 path parameter
로 입력받은 값과 일치하는 것으로 보내기!
정말 신기하게도,
parseInt
는+
하나로도 표현할 수 있다.parseInt(id) === +id
👉🏻 what is
parseInt
?
: convert object type from string to number(int)
deleteOne 함수는 이런식으로 작성하기! 삭제 여부에 대한 값을 리턴해야 해서 그런것인지
리턴보낼 타입이 boolean
이다.
create 함수는 현재 존재하는 id의 값을 늘려주고, spread
연산자를 사용해서 movie 데이터를 넣어준다.
아직 movieData의 타입을 명시해주지 않은 상태!
아무튼, 그래서 어떻게 Service
에 있는 함수들을 Controller
에서 부를 수 있을까?
👆🏻 express.js, 여타의 프레임워크들과 다르게 NestJS는 수동으로 import 하지 않는다.
import 구간에 있는 것들은 데코레이터로 사용되는 것들!
👆🏻 Controller
하위에 constructor
로 명시해주면 이제 Controller
내부에서 this
를 통해 사용할 수 있다.
어떠한 값을 리턴받을지를 함수명 옆에 명시해주고, 리턴값 수정해주기!
늘 그렇듯, 함수 작성 시 예외처리는 필수로 해주어야 한다.
getOne 함수를 통해서 살펴보자. 만약 리턴보낼 데이터가 존재하지 않는다면?
const Movie
객체의 값이 없다면 NestJS가 이미 만들어둔 기능을 통해 예외처리를 할 수 있다.
deleteOne 함수를 통해 살펴보는 boolean을 리턴하는 경우!
getOne 함수를 호출함으로서, 만에 하나 에러가 발생하는 경우 예외처리가 발생하게 된다.
(this.movies = this.movies.filter(movie => movie.id !== +id);
)라고 해주어야 함
deleteOne(id: string){
this.getOne(id);
this.movies = this.movies.filter(movie => movie.id !== +id);
}
사실 이런식으로 리턴보낼 값도, 리턴부분도 작성해주지 않아도 된다고.
앞서 우리가 타입을 정해주지 않았던 객체들에게 타입을 부여해줄 때가 왔다.
what is
DTO
?
👉🏻 Data Transfer Object
: 데이터 전송 객체!
입력받을 데이터들의 자료형
을 명시해준다.
id의 경우는 client
에서 입력받는 것이 아니므로 입력하지 않는다.
DTO
를 사용하므로서, 프로그래머로서 더욱 간결한 코드를 작성할 수 있고,
NestJS가 들어오는 쿼리에 대해 유효성을 검사할 수 있도록 한다.
유효성 검사를 하기 위해, main.ts
파일 내에 파이프를 생성해준다.
이제 ValidationPipe
와 이를 사용해서 검사하는 DTO
를 생성할 수 있다.
Pipe란, 말 그대로 내가 작성한 코드가 지나가는 통로!
ValidationPipe
에는 많은 기능들이 있는데,
1. 아예 잘못된 값이validatior
까지 가지 못하게 하는whitelist
2. 이상한 값이 오면request
자체를 막아버리는forbidNonWhitelisted
3.request
때마다 실제 데이터 타입으로 변환하는transform
npm i class-validator class-transformer
👆🏻 해당 명령어를 입력해서 유효성 검사를 위한 dependencies들을 설치하자 👇🏻(클래스 유효성 검사용)
이제 해당 DTO
를 가지고 readonly
속성의 작업을 할 수 있다.
DTO
s and Validation
part Two앞서 작성한 DTO
는 readonly
속성이기 때문에, update작업을 하기에는 적절하지 않다.
그래서 Update 작업만 하기 위한 DTO
를 생성해줄 것!
update를 하기 위한 DTO
는 모든 값들이 필수 조건이 아니다.
때에 따라서 변경될 값들이 다를 수 있기 때문!
NestJS의 부분 타입(partial types
) 기능을 활용해서 작성해보자.
npm i @nestjs/mapped-types
우선, 타입을 변환시키고 사용할 수 있게 하는 mapped-types
패키지를 설치하기! (DTO
를 변환시키는 것을 도와준다)
partialTypes
를 통해서, 기존 DTO
와 똑같긴 하지만 필요에 따라 수정할 수 있는 DTO
를 생성할 수 있다.
이제 기존에 작성해둔 DTO
를 약간 수정해보자. genre항목을 매번 입력받지 않아도 되게 하고싶으므로
class-validator
의 속성들 중 IsOptional
데코레이터를 사용해보기!
Typescript
,NestJS
를 사용하면서 좋은 점?👉🏻 우리의 서버를 실시간으로 보호할 수 있다!
👉🏻NestJS
를 쓰면서Typescript
의 보안을 사용할 수 있고, 유효성 검사를 따로 하지 않아도 되기 때문
우리의 모듈 구조를 조금 더 사용하기 좋게 만들어보자
이전에 app.module
이 controllers : [Controller]
, providers: [Service]
를 가지고 있던 것을 기억하나요!!
사실은, NestJS에서 앱은 여러 모듈을 가지며, 각 모듈은 해당하는 Controller, provider만 가지고 있어야 한다.
app.module
은 AppController
, AppProvider
만 가져야하는 것이 옳다.
이런 기준이라면, movie.module
을 생성해서 MovieController
, MovieService
를 담아주는 것이 옳을 것!
터미널에서 nest g mo
명령어를 입력하고, 모듈 명을 입력하면 모듈이 생성되고,
app.module
내부에 @Module
데코레이터 하위에 ...Module
이 import된 것을 볼 수 있다.
MoviesModule
에 관련된 것들은 모두 삭제해준 뒤, 해당 내용들을 MoviesModule
내부로 옮겨준다.
앱을 생성할 떼, 모듈로 분리해주어야 하기 때문에 프로젝트를 구성할 때 이런한 방식으로,
app.mopdule.ts
가 다른 모듈들을 import하는 형식으로 만들어야 한다.
언제
app.module
을 사용하나요?👉🏻 Thanks to the NestJS's way of building architecture of our application,
when NestJS starts the application, it will create one module(Module
) for everything!
appModule
하나를 통해서, 모든것을 생성할 수 있다.
Dependency Injection
?
module
파일 내부에 Controller, Service 를 명시해주는 것을 통해
Controller, Service 내부에서@Injectable
데코레이터를 통해 각각의 파일들을 사용할 수 있게 된다.
NestJS가 알아서 import 해줌
👆🏻 기반으로 돌아가기 때문에 Controller
, Service
에서도 필요에 따라 Response
, Request
를 사용할 수 있다.
Res
, Req
사용해주면 Express앱에 접속할 수 있다고 한돠..
하지만 이러한 Express 객체를 직접적으로 사용하는 것은 좋은 방법이 아니다.
NestJS는 Express 에서 실행되지만, 이를 Fastify라는 라이브러리로 전환시킬수도 있다고 한다. 👉🏻
NestJS - Performance (Fastify)
Express에서 response 객체를 사용하는 방법 (NestJS에서 Express앱에 접근하는 기본적 방식)
👉🏻 플랫폼, 어플리케이션에서Req
,Res
같은 데코레이터를 이용해서 Express에 접근할 수 있다.
👉🏻res.json()
🥵 (But Express, Fastify를 사용한다면 쓰지 않는 것이 좋다. 프레임워크 전환 시 문제됨)