[ NestJS ] API 만들기 (2) - REST API 생성하기

Hailee·2021년 1월 17일
1

[ NestJS ]

목록 보기
3/3
post-thumbnail
post-custom-banner

2.0 Controller 만들기

  • url을 가져오고, function을 실행하는 파일 만들기!

이미 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 어플리케이션에서의 라우터들

Path Parameter

url에 있는 아이디를 얻고 싶다면? 무언가가 필요하면 우리가 요청해아한다.
앞서 RESTful한 개발에서 사용했던 path parameter!를 생각해보면
localhost:포트번호/movies/3 👉🏻 parameter를 요청하는 것!


👆🏻 "id라는 paramater를 id라는 argumentstring 타입으로 저장" 이라는 뜻

path parameter로 받을 값과 param으로 가져오는 값은 같게 명시해주어야 하지만,
string 타입으로 받고싶은 값은 마음대로 명명할 수 있다.

controller에서 사용되는 HTML 메서드들을 알아보자

  • Get, Post, Delete, Put, Update

Put

  • 모든 리소스를 업데이트한다.

Patch

  • 리소스의 일부분만 업데이트한다. (path parameter로 요청)

2.1 More Routes

단순히 URL에 parameters만 추가해서 보내는 것 말고도, request를 보낼 때 body에 다른 값들을 담아서 보내보고 싶다면?
👉🏻 @Body를 사용하면 된다.

👉🏻 해당 데코레이터를 통해 movieData 안의 requestBody를 가져오기 위한 것!

이러한 개념은 Patch메서드를 사용할 때 사용된다.
Patch일부분만 업데이트되기 때문에, 업데이트 할 대상을 특정지을 parameter를 꼭 받아와야한다.

요로케 입력받을 값들을 데코레이터를 활용해서 명시해두고,
Spread 연산자를 활용해서 리턴값을 적어주면 다음과 같은 리턴값을 확인할 수 있다. 👇🏻

Query String

검색 등의 기능을 구현할 때를 감안해서 Query String을 입력받는 경우를 생각해보자.

이런 검색조건을 걸고싶은 경우를 살펴보자.

localhost:포트번호/search?year=2000

/search라는 경로를 가지는 함수보다 :id라는 파라미터를 받는 함수가 먼저 나와있는 경우,

Get데코레이터로 된 pathParameter를 받는 함수가 먼저 나와있으면
그 이후의 함수들이 작동하지 않는다고 한다
(NestJS, express.js를 사용하면 겪는 일이라고 한다.)

그렇기 때문에 요로케, 순서를 잘 신경써서 작성해줘야 한다는 것!
path parameter@Param 데코레이터로 받은 것처럼, query string@Query 데코레이터로 받아주어야 한다.


2.2 Movies Service part One

Single-responsibility principle

  • 하나의 module, class, function이 하나의 기능은 꼭 책임져야 한다!

Controller가 url 매핑, request 받기, Query,Param,Body 넘기기, 등의 작업을 한다면
Service는 로직을 작성하고 관리한다.

우리가 작업하는 디렉토리 내에 새로운 폴더를 생성하고, 데이터베이스를 사용한다고 가정하기 위해 가짜 데이터 파일을 생성한다.

👉🏻👉🏻JS에서 export, import란 무엇일까?

함수명 옆에 어떠한 값을 리턴해줄 지를 명시해주고
return 부분에 실제 리턴값을 적어준다.

getOne 함수의 경우, string 타입id라는 값을 받고, Movie 객체를 리턴해주는데
리턴해주는 이 값은 앞서 선언해둔 movies 데이터 파일에서 movie.idpath 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를 통해 사용할 수 있다.
어떠한 값을 리턴받을지를 함수명 옆에 명시해주고, 리턴값 수정해주기!

  • 어떠한 값을 리턴받을지를 적어주는 부분을 타입을 적어준다고 하던데, 이게 혹시 typescript인가 싶다
    얼른 타입스크립트 공부하러 가야쥐

2.3 Movies Service part Two

늘 그렇듯, 함수 작성 시 예외처리는 필수로 해주어야 한다.
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);
}

사실 이런식으로 리턴보낼 값도, 리턴부분도 작성해주지 않아도 된다고.


2.4 DTOs and Validation part One

앞서 우리가 타입을 정해주지 않았던 객체들에게 타입을 부여해줄 때가 왔다.

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 속성의 작업을 할 수 있다.


2.5 DTOs and Validation part Two

앞서 작성한 DTOreadonly 속성이기 때문에, 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의 보안을 사용할 수 있고, 유효성 검사를 따로 하지 않아도 되기 때문


2.6 Modules and Dependency Injection

우리의 모듈 구조를 조금 더 사용하기 좋게 만들어보자
이전에 app.modulecontrollers : [Controller], providers: [Service]를 가지고 있던 것을 기억하나요!!

사실은, NestJS에서 앱은 여러 모듈을 가지며, 각 모듈은 해당하는 Controller, provider만 가지고 있어야 한다.
app.moduleAppController, 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 해줌


2.7 Express on NestJS

NestJS runs top of express.js

👆🏻 기반으로 돌아가기 때문에 Controller, Service에서도 필요에 따라 Response, Request를 사용할 수 있다.
Res, Req 사용해주면 Express앱에 접속할 수 있다고 한돠..

하지만 이러한 Express 객체를 직접적으로 사용하는 것은 좋은 방법이 아니다.
NestJS는 Express 에서 실행되지만, 이를 Fastify라는 라이브러리로 전환시킬수도 있다고 한다. 👉🏻
NestJS - Performance (Fastify)

Express 보다 훨씬 빠르다고 함!

Express에서 response 객체를 사용하는 방법 (NestJS에서 Express앱에 접근하는 기본적 방식)
👉🏻 플랫폼, 어플리케이션에서 Req, Res같은 데코레이터를 이용해서 Express에 접근할 수 있다.
👉🏻 res.json()
🥵 (But Express, Fastify를 사용한다면 쓰지 않는 것이 좋다. 프레임워크 전환 시 문제됨)

profile
웹 개발 🐷😎👊🏻🔥
post-custom-banner

0개의 댓글