728x90
반응형

swagger에 관한 자세한 사항은 아래 링크

https://docs.nestjs.com/openapi/introduction#bootstrap

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com


 

NestJS에서 swagger를 사용하면 아래와 같이 API를 테스트 할 수 있는 GUI 환경을 제공해준다.

 

 

 

일단 NestJS와 Swagger를 설치한다.

$ npm i -g @nestjs/cli
$ nest new teepo
$ npm install --save @nestjs/swagger swagger-ui-express

 

그다음 main.ts에 swagger를 추가해준다.

main.ts

import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = new DocumentBuilder()
    .setTitle('User example')
    .setDescription('The user API description')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('swagger', app, document);

  await app.listen(3000);
}
bootstrap();

SwaggerModule.setup() 메소드 안에서 Swagger UI를 마운트하는 경로를 설정할 수 있다.

 

 

이제 npm run start:dev를 하고 화면(:3000/swagger)을 확인해보자.

$ npm run start:dev

 

 

정상적으로 출력되었다. 이제 api에 문서화를 진행해보자.

 

임의로 user라는 resource를 만들어보겠다.

$ nest g res user

 

 

간단하게 dto 파일을 작성한다.

create-user.dto.ts

export class CreateUserDto {
    name : string;
    age : number;
}

 

 

userController 파일을 다음과 같이 수정해보자.

user.controller.ts

import { Controller, Response, Get, Post, Body, Patch, Param, Delete, Res, HttpStatus } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { ApiCreatedResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { User } from './entities/user.entity';

@Controller('user')
@ApiTags('유저 API')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  @ApiOperation({summary : '유저 생성 API', description: '유저를 생성한다.' })
  @ApiCreatedResponse({description: '유저를 생성한다', type: User})
  async create(@Body() createUserDto: CreateUserDto) {
    const user: User = await this.userService.createUser(createUserDto);
    return user;
  }
}

 

userController에서 쓰일 userService를 정의한다.

user.service.ts

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UserService {
  createUser(createUserDto: CreateUserDto) {
    return {
      name : 'teepo',
      age : 28
    };
  }

}

 

 

이제 실행 화면을 보면

 

 

이렇게 우리가 추가한 '유저 API'가 잘 생성된 것을 볼 수 있다. 오른쪽 Try it out 버튼을 클릭하면 테스트 화면이 나온다.

일단 아무것도 입력하지 않고 바로 보내보자.

 

 

결과화면 : 

 

 

Service에 작성했던 정보가 잘 넘어온 것을 확인할 수 있다. 

 

dto와 클래스 또한 Swagger를 사용해 정의할 수 있다. 타입도 지정해주고 확인해주자.

class-validator와 class-transformer를 설치한다.

$ npm i class-validator class-transformer

 

 

dto 파일에 타입과 swagger 데코레이터를 추가한다.

create-user.dto

import {IsString, IsNumber} from 'class-validator'
import { ApiProperty } from '@nestjs/swagger';

export class CreateUserDto {
    @ApiProperty({ description: '이름' })
    @IsString()
    name : string;

    @ApiProperty({ description: '나이' })
    @IsNumber()
    age : number;
}

 

 

main.ts에 파이프를 설정해준다.

main.ts

import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = new DocumentBuilder()
    .setTitle('User example')
    .setDescription('The user API description')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('swagger', app, document);

  app.useGlobalPipes(
    new ValidationPipe({
      whitelist : true, 
      forbidNonWhitelisted : true,
      transform : true
    })
  )

  await app.listen(3000);
}
bootstrap();

 

Service부분에 내가 입력한 값 그대로를 반환하게끔 수정해준다.

user.service.ts

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UserService {
  createUser(createUserDto: CreateUserDto) {
    return createUserDto
  }

}

 

 

이제 다시 화면을 보면 DTO에 설정해두었던 타입들이 잘 들어가는 것을 확인할 수 있다.

 

 

 

맨 아래쪽에 스키마 부분도 설명이 잘 되어있다.

 

 

 

이번엔 타입과 다른 값을 보내보자. name에 string대신 number를 보내줄 것이다.

 

 

 

결과를 확인해보면

 

 

"name must be a string" 이라는 문구를 확인할 수 있다.

728x90
반응형

'Back-End > Nest.js' 카테고리의 다른 글

Nest.js | Middleware  (0) 2021.10.28
Nest.js | MongoDB | PATCH and DELETE  (0) 2021.10.06
Nest.js | MongoDB | Create  (0) 2021.10.06
Nest.js | MongoDB | Find  (0) 2021.10.06
Nest.js | MongoDB | Model,Schema,Controller  (0) 2021.10.06
728x90
반응형

DELETE와 PATCH도 추가해보자.

DELETE를 먼저 테스트 수행하면 남아있는 데이터가 없기 때문에 PATCH부터 작성한다.

 

  describe('/movies/:id',() => {
    it('GET 200', () => {
      return request(app.getHttpServer())
        .get('/movies/1')
        .expect(200)
    });
    it('GET 404', () => {
      return request(app.getHttpServer())
        .get('/movies/999')
        .expect(404)
    });
    it('PATCH 200', () => {
      return request(app.getHttpServer())
        .patch('/movies/1')
        .send({ title : 'Updated Test'})
        .expect(200)
    });
    it('DELETE 200', () => {
      return request(app.getHttpServer())
        .delete('/movies/1')
        .expect(200);
    });
  });

 

테스트를 수행해보면

 

정상으로 작동했다.

 

이번에는 잘못된 데이터를 가진 movie를 create하는지 테스트해보자.

  describe('/movies', () => {
    it('GET',() => {
      return request(app.getHttpServer())
        .get('/movies')
        .expect(200)
        .expect([]);
    });

    it('POST 201',() => {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          title: 'Test Movie',
          genres: ['test'],
          year: 2000
        })
        .expect(201)
    });

    it('POST 400',() => {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          title: 'Test Movie',
          genres: ['test'],
          year: 2000,
          other: "thing"
        })
        .expect(400)
    });

    it('DELETE', () => {
      return request(app.getHttpServer())
        .delete('/movies')
        .expect(404)
    });
  });

 

테스트를 수행해보면

 

 

정상적으로 작동하였다.

728x90
반응형
728x90
반응형

 

우리가 테스트를 진행하는 동안에 테스트를 마치고 다른 테스트를 진행할 때 항상 만들어 두었던 데이터베이스가

사라졌었다.( 새로운 테스트 진행마다 앱이 새로 생성됨 ) 이 과정이 귀찮으면 beforeAll Hook을 추가할 수 있다.

 

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

 

이 부분의 beforeEach를 beforeAll로 바꿔준다. 그다음 GET 메서드에서 id로 getOne함수를 사용하는 부분을 추가하자.

 

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('this is home');
  });

  describe('/movies', () => {
    it('GET',() => {
      return request(app.getHttpServer())
        .get('/movies')
        .expect(200)
        .expect([]);
    });

    it('POST',() => {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          title: 'Test Movie',
          genres: ['test'],
          year: 2000
        })
        .expect(201)
    });

    it('DELETE', () => {
      return request(app.getHttpServer())
        .delete('/movies')
        .expect(404)
    });
  });

  describe('/movies/:id',() => {
    it('GET 200', () => {
      return request(app.getHttpServer())
        .get('/movies/1')
        .expect(200)
    })
  })

});

 

/movies/:id에 200 status를 받게끔 코딩하고 테스트를 진행해보면

 

이렇게 에러가 뜨는 것을 확인할 수 있다. 왜 그럴까?

 

실제 서버에서 돌아갈 때는 id가 number라고  뜬다(main.ts에서 transform을 써서 number로 받아옴)

하지만 테스팅 서버에서는 

어떤 pipe에도 올리지 않았다.

 

main.ts에서 적용했던 것처럼 테스팅서버에서도 적용하고 실행해보자.

 

 

아주 잘 작동하는것을 확인할 수 있다.

728x90
반응형
728x90
반응형

유닛 테스트를 좋아하는 사람들이 있는 반면에 e2e 테스트를 좋아하는 사람들도 있다.

e2e테스트는 유닛 테스트할 때처럼 하나하나 테스트하지 않는다.

 

 

먼저 Nest 앱을 만들 때 자동으로 만들어진 이 파일들 부터 보면

 

app.e2e-spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Hello World!');
  });
});

 

 

여기서 유닛테스트를 할 때와는 다르게 it함수 안 쪽에 '/'에 GET method로 들어오는 요청들에 대해 테스트를 한 다는것을 볼 수 있다. 이는 Controller, Service, Pipe의 결과에 대해 모든 테스트를 하고 있다는 뜻이기도 하다.

 

일단 먼저 e2e테스트를 실행해보자.

$ npm run test:e2e

 

 

 

실패다. 자세히 읽어보면

이 부분에서 우리가 루트 경로에 지정했던 문자열과 테스트할 때의 문자열이 다른것을 확인 할 수 있다.

 

app.controller.ts

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

@Controller('')
export class AppController {
    @Get()
    home() {
        return 'this is home'
    }
}

 

때문에 "Hello World!" 였던 부분을 "this is home"으로 바꿔서 다시 실행해보자.

 

app.e2e-spec.ts

it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('this is home');
  });

 

테스트를 실행해보자.

 

'/' GET 으로 'this is home' 이라는 반환 값을 성공적으로 받았다.

 

이번엔 movies에서 코드를 추가하고 적용해보자

  it('/movies (GET)',() => {
    return request(app.getHttpServer())
      .get('/movies')
      .expect(200)
      .expect([]);
  })

 

테스트를 해보면

 

 

정상적으로 테스트가 진행되었다.

유닛테스트를 할 때 처럼 좀 더 깔끔하게 다듬어서 POST까지 테스트해보자.

 

app.e2e-spec.ts

  describe('/movies', () => {
    it('GET',() => {
      return request(app.getHttpServer())
        .get('/movies')
        .expect(200)
        .expect([]);
    });

    it('POST',() => {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          title: 'Test Movie',
          genres: ['test'],
          year: 2000
        })
        .expect(201)
    });
  });

 

테스트를 해보면

성공하였다. 이번엔 DELETE까지 추가해보자.

    it('DELETE', () => {
      return  request(app.getHttpServer())
        .delete('/movies')
        .expect(404)
    });

 

 

이렇게 GET, POST, DELETE 메소드 별로 테스트를 해보았다.

728x90
반응형
728x90
반응형

마지막인 Update를 테스트 하기 위해 코드를 추가해보자.

  describe("update", () => {

    it("should update ", () => {
      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)
      }
    });

  });

 

테스트 결과를 확인해보면!

 

 

정상적으로 수행되었다.

728x90
반응형
728x90
반응형

계속해서 이번엔 Delete와 Create를 테스트 해보자.

 

  describe("deleteOne", () => {

    it("deletes a movie", () => {
      service.create({
        title:"Test Movie",
        genres: ['test'],
        year: 2000
      });
      const allMovies = service.getAll().length;
      service.deleteOne(1);
      const afterDelete = service.getAll().length;
      expect(afterDelete).toBeLessThan(allMovies);
    });

  });

 

한 개의 데이터를 삭제 했으니 기존의 것보다 개수가 줄었다는 것을 테스트한다.

404 error 까지 코드를 추가하고 테스트를 실행해보자.

 

  describe("deleteOne", () => {

    it("deletes a movie", () => {
      service.create({
        title:"Test Movie",
        genres: ['test'],
        year: 2000
      });
      const allMovies = service.getAll().length;
      service.deleteOne(1);
      const afterDelete = service.getAll().length;
      expect(afterDelete).toBeLessThan(allMovies);
    });
    it("should throw 404 error", () => {
      try {
        service.deleteOne(999);
      }
      catch(e){
        expect(e).toBeInstanceOf(NotFoundException)
      }
    })

  });

 

 

이처럼 테스트가 정상 작동하는 것을 볼 수 있다.

 

Create도 마찬가지로 추가하고 테스트를 진행해보자.

  describe("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)
    })

  })

 

728x90
반응형
728x90
반응형

참조

https://nomadcoders.co/nestjs-fundamentals/lectures/1953

 

All Courses – 노마드 코더 Nomad Coders

초급부터 고급까지! 니꼬쌤과 함께 풀스택으로 성장하세요!

nomadcoders.co

 

pakage.json 파일을 보면 테스팅과 관련된 스크립트가 5가지 정도 있다.

 

 

먼저 jest는 자바스크립트를 아주 쉽게 테스팅하는 npm 패키지이다.

 

우리가 controller나 service를 만들 때, 이러한 파일들을 볼 수 있었는데

이것이 바로 테스트를 포함한 파일이다.

Nest.js에선 jest가 .spec.ts 파일들을 찾아볼 수 있도록 설정 되어 있다.

 

아래 명령어를 입력해보자.

$ npm run test:cov

 

 

그럼 이런식으로 테스트가 진행된 것을 확인할 수 있다. 이렇게 ts 파일들을 테스트 할 수 있다.

 

 

이번에는 유닛 테스팅을 해보자. 유닛테스팅은 모든 function을 따로 테스트하는 것이다.

예를들면 getAll() function 하나만 테스트하고 싶을 때 사용한다.

 

e2e 테스팅은 특정 링크로 가면 특정 페이지가 나와야하는 경우 사용한다.

728x90
반응형
728x90
반응형

이전까지 만들었던 모듈을 좀 더 좋은 구조로 만들어보자.

 

app.module.ts

우린 이런 식으로 Controller와 Service를 하나씩 만들었었다.

먼저 모듈을 생성한다는 아래 명령어를 실행해보자.

$nest g mo

 

그다음 이름을 movies로 하게 되면 아래와 같이 되는 것을 확인할 수 있다.

 

먼저 app.module.ts에 먼저 담겨있던 controller와 providers를 삭제한다.

 

app.module.ts

import { Module } from '@nestjs/common';
import { MoviesController } from './movies/movies.controller';
import { MoviesService } from './movies/movies.service';
import { MoviesModule } from './movies/movies.module';

@Module({
  imports: [MoviesModule],
  controllers: [],
  providers: [],
})
export class AppModule {}

 

 

 

그다음 movies.module.ts를 아래와 같이 수정해보면 우리는 controller와 providers를 가진 모듈 한 개를 완성한 것이다.

 

movies.module.ts

import { Module } from '@nestjs/common';
import { MoviesController } from './movies.controller';
import { MoviesService } from './movies.service';

@Module({
    controllers: [MoviesController],
    providers: [MoviesService]
})
export class MoviesModule {

}

 

 

 

자 그럼 루트 모듈인 app.module.ts에서의 controllers와 providers는 언제 사용이 될까?

먼저 아래 명령어를 실행해서 app.controller.ts를 생성하고 이름을 app이라 지어준다.

 

$nest g co

 

그다음 app.controller.ts를 아래 사진과 같이 옮기고 app 폴더를 삭제한다.

 

 

app.controller.ts

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

@Controller('app')
export class AppController {}

 

처음 만들 때의 controller의 모습은 위의 코드와 같다.

우리가 첫 라우트 path를 지정할 때  @Controller 안에 이름을 지정을 했었는데, 지금까지 루트 라우터는 없었다.

루트 라우터를 만들어줄 차례다.

 

app.controller.ts

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

@Controller('')
export class AppController {
    @Get()
    home() {
        return 'this is home'
    }
}

이렇게 코드를 바꿔주면 home화면에 this is home 글자를 확인할 수 있을 것이다.

728x90
반응형
728x90
반응형

 

전 글에서 movieData DTO를 만들어봤다.

이번 글에선 updateData DTO를 만들어보겠다.

 

먼저 update-movie.dto.ts 파일을 만든다.

 

update-movie.dto.ts

import {IsString, IsNumber} from 'class-validator'

export class CreateMovieDto {
    @IsString()
    readonly title?: string;

    @IsNumber()
    readonly year?: number;
    
    @IsString({each:true})
    readonly genres?: string[];
}

 

movieData의 DTO와 다른 점은 물음표가 있다는 점인데, 이는 필수사항은 아니게 한다는 뜻이다.

 

그다음 Controller와 Service에 추가하는 방법까지는 똑같다.

여기서 우리는 부분 객체라는 것을 써볼 것이다. 먼저 아래와 같이 설치해준다.

$npm i @nextjs/mapped-types

 

 

그다음 PartialType을 사용하기 위해 코드를 바꿔준다.

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

export class UpdateMovieDto extends PartialType(CreateMovieDto) {}

 

 

이런식으로 CreateMovieDto를 상속할 수 있게 만들 수 있다. 또한 각각의 요소가 필수사항이 아니게끔 만들어준다.

 

이렇게 하고 POST 메소드로 Create하고 PATCH로 업데이트를 실행해보면 성공!

728x90
반응형
728x90
반응형

 

updateData랑 movieData한테 타입을 부여하기 위해서 우리는 DTO(Data Transfer Object, 데이터 전송 객체)를 만들어야한다. 먼저 create-movie.dto.ts 파일을 만들자.

 

 

create-movie.dto.ts

export class CreateMovieDto {
    readonly title: string;
    readonly year: number;
    readonly genres: string[];
}

 

 

그 다음 Controller 부분과 Service 부분에 타입을 추가해주자. (movieData)

 

Controller

    @Post()
    create(@Body() movieData : CreateMovieDto) {
        return this.moviesService.create(movieData);
    }

 

Service

    create(movieData:CreateMovieDto) {
        this.movies.push({
            id: this.movies.length + 1,
            ...movieData
        })
        return true;
    }

 

이렇게 해두면 아래와 같이 movieData. 만 입력해도 클래스가 가진 속성들이 자동으로 나와서 코딩하기에도 편리하다.

또한 타입에 대한 유효성을 검사할 수도 있다.

 

클래스의 유효성 검사를 위해 main.ts에 다음과같이 pipe를 만들어주겠다.

 

main.ts

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe()
  )
  await app.listen(3000);
}
bootstrap();

 

 

또한 아래 명령어를 입력해서  npm 모듈을 설치하자.

$npm i class-validator class-transformer

 

그다음 아까 만들어두었던 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})
    readonly genres: string[];
}

 

 

 

그 다음 postman에서 다음과 같이 POST 메소드로 {hacked: "by me"} 라는  body를 요청해보면 이런 결과창이 뜬다.

 

ValidationPipe 와 CreateMovieDto를 사용하고 있기 때문에 DTO의 타입을 실시간으로 확인할 수 있는 것이다.

 

ValidationPipe의 옵션 중 유용한 옵션인 whitelist라는 것이 있는데,

true로 설정하면 아무 Decoreator도 없는 어떠한 property의 object를 거룰 수 있다.

 

또한 보안을 위해 forbidNonWhitelisted 라는 옵션도 있다. 

이는 정의를 하지 않은 데이터가 error메세지에 뜨게끔 도와준다

 

transform라는 옵션은

보통 데이터를 body로 받을 때 string으로 받아서 정수형은 parseInt를 써야 했지만,

그럴 필요 없이 바로 원하는 자료형으로 바꿔주는 기능을 한다.

 

 

여기까지 추가를 해보면

 

 

main.ts

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist : true, 
      forbidNonWhitelisted : true,
      transform : true
    })
  )
  await app.listen(3000);
}
bootstrap();

 

 

이렇게 되고, 추가했었던 parseInt를 바꿔주면 된다.

 

movies.controller.ts

import { Controller, Get, Param, Post, Delete, Patch, Body, Query } from '@nestjs/common';
import { CreateMovieDto } from './dto/create-movie.dto';
import { Movie } from './entities/movie.entity';
import { MoviesService } from './movies.service';

@Controller('movies')
export class MoviesController {
    constructor(private readonly moviesService: MoviesService) {}

    @Get()
    getAll(): Movie[] {
        return this.moviesService.getAll();
    }

    @Get('/:id')
    getOne(@Param('id') movieId: number){
        return this.moviesService.getOne(movieId)
    }

    @Post()
    create(@Body() movieData : CreateMovieDto) {
        return this.moviesService.create(movieData);
    }

    @Delete('/:id')
    remove(@Param('id') movieId:number) {
        return this.moviesService.deleteOne(movieId);
    }

    @Patch('/:id')
    patch(@Param('id') movieId:number, @Body() updateData) {
        return this.moviesService.update(movieId,updateData)
    }
}

 

 

movies.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { NotFoundError } from 'rxjs';
import { CreateMovieDto } from './dto/create-movie.dto';
import { Movie } from './entities/movie.entity';

@Injectable()
export class MoviesService {
    private movies: Movie[] = [];

    getAll(): Movie[] {
        return this.movies;
    }

    getOne(id:number): Movie {
        
        const movie = this.movies.find(movie => movie.id === id);
        if(!movie) {
            throw new NotFoundException(" ID가 존재하지 않습니다. ")
        }

        return movie;

    } 

    deleteOne(id:number) {
        this.getOne(id)
        this.movies = this.movies.filter(movie => movie.id !== id)
    }

    create(movieData:CreateMovieDto) {
        this.movies.push({
            id: this.movies.length + 1,
            ...movieData
        })
        return true;
    }

    update(id: number, updateData) {
        const movie = this.getOne(id);
        this.deleteOne(id)
        this.movies.push({ ...movie, ...updateData})
    }

}

 

728x90
반응형

+ Recent posts