Study/Backend

[Nomard Coder] NestJS로 API 만들기

안다희 2021. 2. 8. 00:26
728x90

완성코드

핵심

  • 앱은 여러 개의 모듈로 구성됨.
    • 모듈은 컨트롤러와 서비스로 구성됨.
    • 컨트롤러는 url을 가져오고 함수를 실행한다.
    • 서비스는 실제로 function을 가지는 부분이다. 필요하다면 db에 접근도 한다.

0.1 Welcome

  • node.js 위에서 움직이는 프레임워크. (사실 express 위에서.)
  • node.js에 서버 구성할 수 있게 해줌.
  • 다른 node.js 프레임워크에는 없는 구조를 가지고 있다.
  • nest.js는 구조가 있다. 그것을 따르기만 하면 큰 규모의 백엔드를 쉽게 만들 수 있다.
  • nest.js 배우면 express.js로 돌아갈 수 없다!
  • node.js는 구조가 없어 자유롭다.
  • express의 미들웨어와 같은 것이다.
  • 결론: 아주 좋은 아키텍처를 가지고 있다.

0.2 Requirements

0.3 Project Setup

npm i -g @nestjs/cli    
nest new

1.0 Overview

  • nestjs는 이미 만들어진 기능을 제공한다.
  • typescript도 이미.
  • src/app.controller.spec.ts는 삭제한다.
  • 남는건 main, module, controller, service
npm run start:dev
  • nest 어플리케이션 시작 중 => localhost:3000 으로 갈 수 있다.
  • 무조건 main.ts 파일을 가진다. 이 파일로부터 nestjs가 시작한다.
  • app.module.ts
  • 데코레이터는 클래스에 함수 기능을 추가할 수 있다.
    • 클래스 위의 함수. 클래스를 위해 움직인다.
  • module - controller - service

1.1 Controllers

  • 모듈은 어플리케이션의 한 부분.
  • 인증 담당 어플리케이션이 있다면 그게 users 모듈이 될 것이다.
  • 인스타그램을 만든다면 photos, videos 모듈이 필요하겠지?
  • 컨트롤러: url을 가져오고 함수를 실행한다. express의 라우터 같은 존재다.
  • 코드1) app.controller.ts
    • http://localhost:3000/hello url로 가보면 "Hello everyone"이 보일 것이다.
    • 라우터를 세팅하지 않아도, @Get이라고만 해도 get 리퀘스트를 얻을 수 있다.
  • @Get('/hello') sayHello(): string { return 'Hello everyone'; }

1.2 Services

  • 코드1처럼 그냥 string을 리턴하면 되는데 왜 service가 필요할까?
  • 컨트롤러는 그냥 url을 가져오는 역할. 나머지 비즈니스 로직은 서비스로 간다.
  • 서비스: 실제로 function을 가지는 부분이다. 필요하다면 db에 접근도 한다.
  • app.module.ts에서 AppController, AppService 삭제하자. 처음부터 다시!
  • app.controller.ts, app.service.ts도 삭제.

2.0 Movies Controller

  • url을 가져오고 function을 실행하는 파일을 만들 것이다. => controller를 만들 것이다!=> 자동으로 src/movies 폴더가 생긴다. spec.ts 파일은 삭제.
  • nest g co // 이름은 movies
  • movies.controller.ts
  • import { Controller, Get } from '@nestjs/common'; @Controller('movies') export class MoviesController { @Get() getAll() { return 'This will return all movies'; } @Get('/:id') getOne(@Param('id') id: string) { // id: string은 movieId: string여도 상관없다. return `This will return one movie with the id: ${id}`; } }
@Controller('movies') // ()로 바꾸면 localhost:3000/ 루트 url로 바뀐다.
  • 이기 때문에 /movies url로 가야 보인다.
  • Insomnia에서도 확인 가능

  • movies.controller.ts - get, post, delete, patch
  • import { Controller, Get, Param, Post, Delete, Patch } from '@nestjs/common'; @Controller('movies') export class MoviesController { @Get() getAll() { return 'This will return all movies'; } @Get('/:id') getOne(@Param('id') id: string) { // id: string은 movieId: string여도 상관없다. return `This will return one movie with the id: ${id}`; } @Post() create() { return 'This will create a movie'; } @Delete('/:id') remove(@Param('id') id: string) { return `This will delete a movie with the id: ${id}`; } @Patch('/:id') patch(@Param('id') id: string) { // put은 모든 리소스를 업데이트, patch는 일부 리소스만 업데이트 return `This will patch a movie with the id: ${id}`; } }

2.1 More Routes

  • Query
  • @Get('search') search(@Query('year') year: string) { // search가 Get(:id) 보다 밑에 있으면 Get(:id)로 인식한다. // search가 Get(:id)라고 생각하는거지. // http://localhost:3000/movies/search?year=2000 return `We are searching for a movie after: ${year}`; }

2.2 Movies Service part One (10:48)

  • Single reponsibility principle
    • 하나의 module, class 혹은 function이 하나의 기능은 꼭 책임져야한다.
  • make service file
  • nest g s
  • 여기서 생긴 spec.ts는 삭제하지 않는다.
  • 서비스에서는 비즈니스로직, 데이터베이스를 다룰 것이다.
  • 이 강의에서는 js object를 이용하지만, entities에 실제 데이터베이스 모델을 만들어야 한다.
  • src/movies/entities/movie.entity.ts
  • service를 가져오자.
    • express에서 수동으로 import하는 방법이 nestjs에서는 기본적인 방법이 아니다.
    • constructor 이용
  • 최종코드
  • tip
  • const str = '1'; // parseInt('1') === +str; // true

2.3 Movies Service part Two (08:03)

2.4 DTOs and Validation part One (10:52)

  • DTO: Data Transfer Object
  • dto를 쓰는 이유? 코드를 더 간결하게 만들 수 있게 해줌. 들어오는 쿼리에 대해 유효성 검사할 수 있게 해준다.
  • 클래스 유효성 검사를 위해 파이프 만들어줄거다. (미들웨어)
  • 일단 설치할 것들.
  • npm i class-validator class-transformer
  • 유효성 검사 - src/dto/create-movie.dto.ts
  • import { IsString, IsNumber } from 'class-validator'; export class CreateMovieDto { @IsString() readonly title: string; @IsNumber() readonly year: number; @IsString({ each: true }) // Array니까 각각 readonly genres: string[]; }
  • 원하는 타입으로 바꿔준다. (transform 옵션 사용)
  • 프레임워크의 유용성!
  • 최종코드: https://github.com/daheeahn/hi-nest/commit/f86cdbcdc6000a551b804a657bb9d5f3733d581d

2.5 DTOs and Validation part Two (05:34)

  • Create Dto와 다른 점: 필수가 아니라는 점. => PartialType 이용
  • 설치
    • 타입을 변환시키고 사용할 수 있게 해주는 패키지
  • npm i @nestjs/mapped-types
  • update-movie.dto.ts
  • export class UpdateMovieDto extends PartialType(CreateMovieDto) {}
  • 우리의 서버도 실시간으로 보호되고 있다. typescript의 보안을 사용할 수 있다.
  • 최종코드: https://github.com/daheeahn/hi-nest/commit/7bdfe6dd3384b9c098ec990799693ffc4873e8ac

2.6 Modules and Dependency Injection (07:07)

  • app.module.ts에는 AppController, AppService만 있어야 한다. (여러 개 있으면 X)
  • 앱은 여러 개의 모듈로 구성됨.
    • 모듈은 컨트롤러와 서비스로 구성됨.
    • 컨트롤러는 url을 가져오고 함수를 실행한다.
    • 서비스는 실제로 function을 가지는 부분이다. 필요하다면 db에 접근도 한다.
    • nest g mo
  • 컨트롤러와 서비스를 가진 모듈을 만들었다. (app.module.ts 보다 작은 단위의)
  • Service 보면 Injectable 데코레이터가 있다. 이건 컨트롤러에 주입 가능하다는 뜻.
  • Module에서 providers: [MoviesService], 없애면 컨트롤러에는 provider 필요하다고 에러가 난다.
  • 최종 코드: https://github.com/daheeahn/hi-nest/commit/88dbb2a5e6ff61cb319a39af967419e45446714c

2.7 Express on NestJS (03:22)

  • nestjs는 express 위에서 돌아간다. 필요 시 Req, Res 데코레이터 사용 가능.
  • 그러나 이러한 express 객체를 사용하면 좋지 않다. 2개의 프레임워크와 작동하기 때문에
  • 그래서 Fastify라는 걸로 전환시킬 수 있다.
  • Nest는 Fastify 같은 라이브러리와 호환 된다. 이건 express보다 2배 빠르다. 같은 동작 하지만.
  • 항상 nestjs에서는 어떤 방식으로 하는지 알아야 겠지.
  • res.json() 작동할 것이다. (express에서 json 다루는 방식이기 때문에)
  • nestjs만 사용하면 express에서 fastify로 전환 가능. (그렇지만 Res, Req 이건 사용하지 않을 것임)
  • expree와 fastify 전환하고 싶을 때 nestjs가 알아서 해줄 것임. (성능 향상에 좋다)
  • express에 접근 가능. Req, Res 사용 원하면. 그렇지만 추천 X. Fastify처럼 express와는 다른 방법 쓰고 싶을 수 있으니.

 

'Study > Backend' 카테고리의 다른 글

RDBMS와 NoSQL의 차이점  (0) 2023.01.27
[Server] GET과 POST의 param 전달방식이 다르다! in postman  (0) 2019.02.07
출처: https://mingos-habitat.tistory.com/34 [밍고의서식지:티스토리]