NestJS with NomadCoder

커피 내리는 그냥 사람·2021년 4월 14일
0

기업협업 인턴십

목록 보기
4/16

2. REST API 이어서

1. DTO?

상황 : updateData와 movieData에게 타입을 부여하기 위해 서비스와 콘트롤러에 DTO(데이터 전송 객체)

  1. 보낼 수 있는 거, 보냈으면 하는 걸 정리
    (movie/dto/create-movie.dto.ts)
export class createMovieDto{
    readonly title:string;
    readonly year: number;
    readonly genres:string[];}
  1. 이후 서비스와 컨트롤러 살짝 바꿔줌(요청)

  2. 근데 왜 DTO 씀? : 프로그래밍 코드를 더 간결하게 만들어주고 NESTJS에 들어오는 쿼리의 대한 유효성을 검증해줌.

  3. 파이프 만들기(main) : 유효성 검사용, 미들웨어

  • 메인에
  app.useGlobalPipes(
    new ValidationPipe()
  )

추가 후

npm i class-validator, class-transformer 설치

  • dto 파일에 데코레이터 추가
import { IsNumber, IsString } from "class-validator";

export class CreateMovieDto{

@IsString()
    readonly title:string;
@IsNumber()
    readonly year: number;
@IsString({each : true})
    readonly genres:string[];}
  • 마무리 후 포스트맨에서 확인(input의 유효성도 체크)

  • 원천 차단
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist:true,
      forbidNonWhitelisted:true
    })
  )
  • 여기서 transform:true-> 문자로 했던 id들이 죄다 숫자로 바뀜(일일이 다시 바꿔줌)

    타입을 받을 때 스트링을 넘버로 바꿔준 사례, express에서는 일일이 다 해줘야 함

2. updateDate도 변경해주기

  • 앞서 만든 것을 복붙하는데 읽기 전용이고 필수가 아니기 때문에 ? 처리 해줌
    -> 대션 partial type 사용

    npm i @nestjs/mapped-types 설치 후

dto/update-movie.dto.ts

import { IsNumber, IsString } from "class-validator";
import {PartialType} from "@nestjs/mapped-types";
import {CreateMovieDto} from './create-movie.dto';

export class UpdateMovieDto extends PartialType(CreateMovieDto){
}
  • 이 때 기존 create~ 장르 잠시 옵셔널로 놓고 포스트맨 돌리기
@IsOptional()  
@IsString({each : true})
    readonly genres:string[];}

DTO : 유효성 뿐 만 아니라 타입 변경도 가능하다!


3. Module과 Dependency Injection

  • 모듈 구조 조금 더 정갈하게 만들기(movieService, movieController를 모듈로 옮겨보기)
  1. 선행작업

    nest g mo
    이름은 movies

  2. 이후 app.module 내용 일부 지우고 movie.module 수정

import { Module } from '@nestjs/common';
import { MoviesController } from './movies.controller';
import { MoviesService } from './movies.service';
@Module({
    controllers:[MoviesController],
    providers : [MoviesService]
})
export class MoviesModule {}
  • why? : 앱을 분리해서 만드는 것이 유리, app.module에 다 때려 박는 것 지양
  1. 이후

    nest g co
    이름 : app

추가 후 controller만 movie에 가져 옴(나머지는 삭제)

앱모듈 상태

@Module({
  imports: [MoviesModule],
  controllers: [AppController],
  providers: [],
})

(짜여진 앱)

import { Controller, Get } from '@nestjs/common';

@Controller('')
export class AppController {
    @Get()
    home(){
        return 'Welcome!'
    }
}

이 상태로 locall3000 들어가면 나옴

  • nestjs가 앱 구조 짜는 방법이라고 생각하면 됨.(복습 필요)
  1. dependency injection? : 잘 이해 안 됨....
  • 프로바이더의 위치에 따라 값이 출력되고 아니고의 차이인 듯. 다시 보기
  1. Nestjs는 꼭 Express에서만 움직이는 것이 아니다.(Fastify에서도 움직인다.)

    익스프레스에서 쓰던 것 자주 쓰면 좋지 않음

3. UnitTest(e2e는 추후)

  • 유닛 테스트 전 테스트 종류
  • 테스트하고 싶은 파일에 .spec 붙이고

    npm run test:cov 하고 진행

npm run test:watch 하고 진행하면 테스트 파일을 볼 수 있음

  • 그럼 유닛테스트 vs E2E

    서비스에서 분리된 유닛을 테스트하는 것 vs 모든 시스템 테스트

unit : getOne하나만
e2e : 유저 관점에서 취할만 한 전체

1. 첫 번째 유닛 테스트

  • 어떻게 해? : 테스트 작성법부터 (jest사용)
  • movies.service.spec.ts 이용

2. test getAll and getOne in MovieService function

  1. getAll
  describe("getAll()", () => {
    it ("should be return an array", ()=>{

      const result = service.getAll();

      expect(result).toBeInstanceOf(Array)
    })
  })
  1. getOne
  describe("getOne", () => {
   it ("should return a movie", () =>{
    service.create({
      title : "Test Movie",
      genres : ["Test"],
      year : 2000,

    });
  const movie = service.getOne(1);
  expect(movie).toBeDefined();
  expect(movie.id).toEqual(1)
});

it("should throw 404 error", () => {
  try{
    service.getOne(999);
  }catch(e){
    expect(e).toBeInstanceOf(NotFoundException);
    expect(e.message).toEqual(`Movie with ID : 999 NOT FOUND`);
  }
})

  });

(여러 에러 및 예외사항 처리해본 결과)

3. test delete and create

  1. movie를 생성했다가 지웠다가 다시 몇 개 남았는지f 결과 보는 법
      const beforeDelete = service.getAll().length;
      service.deleteOne(1);
      const afterDelete = service.getAll().length;
      expect(afterDelete).toBeLessThan(beforeDelete);
    });

    it("should return a 404 error", ()=> {
      try{
        service.deleteOne(999);
      }catch(e){
        expect(e).toBeInstanceOf(NotFoundException);
      }
    })
  })
  1. create 해보기
    it ("should create a movie", () => {
      const beforeCreate = service.getAll().length
      service.create({
        title : "Test Movie",
        genres : ["Test"],
        year : 2000,
  
      });
      const afterCreate = service.getAll().length
      expect(afterCreate).toBeGreaterThan(beforeCreate);
    })
  })

4. test update

 describe("update", () =>{

  it("should update a movie", () => {
    service.create({
      title : "Test Movie",
      genres : ["Test"],
      year : 2000,
    });
    service.update(1, {title : "Updated Test"});
    const movie = service.getOne(1);
    expect(movie.title).toEqual('Updated Test')
  });
  it("should throw a NotFoundException", ()=> {
    try{
      service.update(999, {});
    }catch(e){
      expect(e).toBeInstanceOf(NotFoundException);
    }
 });
profile
커피 내리고 향 맡는거 좋아해요. 이것 저것 공부합니다.

0개의 댓글