728x90
반응형

이 포스트는 전 포스트에서 이어집니다.

 

 

 

https://docs.nestjs.kr/middleware

 

네스트JS 한국어 매뉴얼 사이트

네스트JS 한국, 네스트JS Korea 한국어 매뉴얼

docs.nestjs.kr


 

Nest 미들웨어는 기본적으로 express 미들웨어와 동일하다. 

 

  • 모든 코드를 실행하십시오.
  • 요청 및 응답 객체를 변경합니다.
  • 요청-응답주기를 종료합니다.
  • 스택의 next 미들웨어 함수를 호출합니다.
  • 현재 미들웨어 함수가 요청-응답주기를 종료하지 않으면 next()를 호출하여 next 미들웨어 기능에 제어를 전달합니다. 그렇지 않으면 요청이 중단됩니다.

 


Request가 들어올 때 로그로 확인하기 위한 미들웨어를 작성해보자.

 

/src/common/middleware/logger.middleware.ts

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
  }
}

 

 

app.module에서 전 포스트에서 작성한 UserModule을 import하고 다음과 같이 수정하자.

app.module.ts

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { LoggerMiddleware } from './common/middleware/logger.middleware';

@Module({
  imports: [UserModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('user');
  }
}

 

이제 Swagger에서 요청을 보내보자.

 

 

콘솔을 확인해보면 미들웨어에서 작성한 내용이 잘 뜨는 것을 확인할 수 있다.

 

미들웨어에서 한 번 들어온 데이터를 검증하고 next()로 넘길 수 있다. 

( 토큰이나 쿠키를 확인하는 것 등)

 

 

logger.middleware.ts

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(req.body)
    next();
  }
}

 

swagger로 요청을 보내보면

 

 

잘 확인되는 것을 볼 수 있다.

 

참고로 이렇게 예외 상황도 만들 수 있다.

consumer
  .apply(LoggerMiddleware)
  .exclude(
    { path: 'cats', method: RequestMethod.GET },
    { path: 'cats', method: RequestMethod.POST },
    'cats/(.*)',
  )
  .forRoutes(CatsController);
728x90
반응형

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

Nest.js | Swagger  (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
반응형

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
반응형

지난글에 이어서 PATCH와 DELETE를 구현해보자.

 

먼저 npm 모듈을 설치하고 UpdateCatDto를 만들어준다.

 

$ npm i @nestjs/mapped-types

 

update-cat.dto.ts

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

export class UpdateCatDto extends PartialType(CreateCatDto) {}

 

Update 먼저 구현해보자.  컨트롤러와 서비스를 바꿔준다.

 

cats.controller.ts

import { Controller, Get, Param, Post, Delete, Patch, Body, Query } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';
import { Cat } from './schemas/cat.schema';


@Controller('cats')
export class CatsController {
    constructor(private readonly catsService: CatsService) {}

    @Get()
    async getAll(): Promise<Cat[]> {
        return await this.catsService.getAll();
    }

    @Get('/:id')
    async getOne(@Param('id') catId: number): Promise<Cat[]> {
        console.log(catId)
        return await this.catsService.getOne(catId);
    }

    @Post()
    async create(@Body() catsData : CreateCatDto) {
        return await this.catsService.create(catsData);
    }

    @Patch('/:id')
    async update(@Param('id') catId: number, @Body() updateData: UpdateCatDto) {
        return this.catsService.update(catId,updateData)
    }

}

 

cats.service.ts

import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cat, CatDocument } from './schemas/cat.schema';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';

@Injectable()
export class CatsService {
  constructor(@InjectModel(Cat.name) private catModel: Model<CatDocument>) {}

  async getAll(): Promise<Cat[]> {
    return await this.catModel.find().exec();
  }

  async getOne(id:number): Promise<Cat[]> {
    return await this.catModel.find({"id" : id});
  } 

  async create(catsData: CreateCatDto) {
    let latestId = await this.catModel.findOne();
    return await this.catModel.create({...catsData, id : parseInt(latestId ? latestId.id : 0)+1});
  }

  async update(id: number, updateData : UpdateCatDto) {
    try {
      await this.catModel.where({"id" : id}).update(updateData);
      return true
    }
    catch(e) {
      return false
    }
  }
}

PATCH 메소드로 요청을 보내보자.


 GetAll()로 확인해보자.

 

정상적으로 id가 1인 데이터의 name이 "초코"로 바뀐 것을 확인할 수 있다.

 

 

DELETE도 만들어보자.

 

cats.controller.ts

import { Controller, Get, Param, Post, Delete, Patch, Body, Query } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';
import { Cat } from './schemas/cat.schema';


@Controller('cats')
export class CatsController {
    constructor(private readonly catsService: CatsService) {}

    @Get()
    async getAll(): Promise<Cat[]> {
        return await this.catsService.getAll();
    }

    @Get('/:id')
    async getOne(@Param('id') catId: number): Promise<Cat[]> {
        console.log(catId)
        return await this.catsService.getOne(catId);
    }

    @Post()
    async create(@Body() catsData : CreateCatDto) {
        return await this.catsService.create(catsData);
    }

    @Patch('/:id')
    async update(@Param('id') catId: number, @Body() updateData: UpdateCatDto) {
        return this.catsService.update(catId,updateData)
    }

    @Delete('/:id')
    async delete(@Param('id') catId: number) {
        return this.catsService.delete(catId);
    }

}

 

cats.service.ts

import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cat, CatDocument } from './schemas/cat.schema';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';

@Injectable()
export class CatsService {
  constructor(@InjectModel(Cat.name) private catModel: Model<CatDocument>) {}

  async getAll(): Promise<Cat[]> {
    return await this.catModel.find().exec();
  }

  async getOne(id:number): Promise<Cat[]> {
    return await this.catModel.find({"id" : id});
  } 

  async create(catsData: CreateCatDto) {
    let latestId = await this.catModel.findOne();
    return await this.catModel.create({...catsData, id : parseInt(latestId ? latestId.id : 0)+1});
  }

  async update(id: number, updateData : UpdateCatDto) {
    try {
      await this.catModel.where({"id" : id}).update(updateData);
      return true
    }
    catch(e) {
      return false
    }
  }

  async delete(id: number) {
    try {
      await this.catModel.remove({"id" : id});
      return true
    }
    catch(e) {
      return false
    }
  }
}

 


postman으로 실행해본다.


getAll() 전체데이터를 확인해본다.

 

 

이렇게 몽고DB로 연결해서 데이터 CRUD 하는 것을 완성하였다.

728x90
반응형

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

Nest.js | Middleware  (0) 2021.10.28
Nest.js | Swagger  (0) 2021.10.28
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
반응형

먼저 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({
      whitelist : true, 
      forbidNonWhitelisted : true,
      transform : true
    })
  )
  await app.listen(3000);
}
bootstrap();

 

그다음 컨트롤러와 서비스를 바꿔주자. GetOne 메소드도 추가하였다.

 

cats.cantroller.ts

import { Controller, Get, Param, Post, Delete, Patch, Body, Query } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CreateCatDto } from './dto/create-cat.dto';
import { Cat } from './schemas/cat.schema';


@Controller('cats')
export class CatsController {
    constructor(private readonly catsService: CatsService) {}

    @Get()
    async getAll(): Promise<Cat[]> {
        return await this.catsService.getAll();
    }

    @Get('/:id')
    async getOne(@Param('id') catId: number): Promise<Cat[]> {
        console.log(catId)
        return await this.catsService.getOne(catId);
    }

    @Post()
    async create(@Body() catsData : CreateCatDto) {
        return await this.catsService.create(catsData);
    }

}

 

cats.service.ts

import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cat, CatDocument } from './schemas/cat.schema';
import { CreateCatDto } from './dto/create-cat.dto';

@Injectable()
export class CatsService {
  constructor(@InjectModel(Cat.name) private catModel: Model<CatDocument>) {}

  async getAll(): Promise<Cat[]> {
    return await this.catModel.find().exec();
  }

  async getOne(id:number) {
    return await this.catModel.find({"id" : id});
  } 

  async create(catsData: CreateCatDto) {
    let latestId = await this.catModel.findOne();
    return await this.catModel.create({...catsData, id : parseInt(latestId ? latestId.id : 0)+1});
  }
}

생성할 때 id가 최근의 id +1 이 되게끔 하였다.

 

2번 생성한 뒤 postman으로 getAll()을 확인해보자.

 

 

 

mongoose에서 Create는 추가한 값을 그대로 반환해준다. 아주 성공적으로 id가 +1씩 되면서 잘 되었다.

 

 

배열 안에 잘 담겨서 반환된 것을 확인할 수 있다.

728x90
반응형

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

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

먼저 다음과 같이 main.ts 파일에 파이프를 추가해준다.

 

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();

 

그다음 controller와 service에 GET메소드로 getAll() 메소드를 만들어보자.

 

cats.controller.ts

import { Controller, Get, Param, Post, Delete, Patch, Body, Query } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CreateCatDto } from './dto/create-cat.dto';
import { Cat } from './schemas/cat.schema';


@Controller('cats')
export class CatsController {
    constructor(private readonly catsService: CatsService) {}

    @Get()
    async getAll(): Promise<Cat[]> {
        return await this.catsService.getAll();
    }


}

 

cats.service.ts

import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cat, CatDocument } from './schemas/cat.schema';
import { CreateCatDto } from './dto/create-cat.dto';

@Injectable()
export class CatsService {
  constructor(@InjectModel(Cat.name) private catModel: Model<CatDocument>) {}

  async getAll(): Promise<Cat[]> {
    return await this.catModel.find().exec();
  }
}

 

postman으로 확인해보자

 

 

아직 추가한 Document가 없기 때문에 당연히 빈배열로 받아와진다.

728x90
반응형

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

Nest.js | MongoDB | PATCH and DELETE  (0) 2021.10.06
Nest.js | MongoDB | Create  (0) 2021.10.06
Nest.js | MongoDB | Model,Schema,Controller  (0) 2021.10.06
Nest.js | MongoDB | Schema  (0) 2021.10.06
Nest.js | E2E TESTING | PATCH and DELETE  (0) 2021.09.30
728x90
반응형

기본적인 cats 모듈,컨트롤러,서비스를 만들고 schemas 폴더를 다음과 같이 옮긴다.

$ nest g module cats
$ nest g co cats
$ nest g s cats

 

 

cats.module.ts 파일을 수정해준다.

cats.module.ts

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { Cat, CatSchema } from './schemas/cat.schema';

@Module({
  imports: [MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }])],
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

 

그 다음 지정된 스키마를 @InjectModel() 데코레이터를 사용하여 CatService에 삽입한다.

cats.service.ts

import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Cat, CatDocument } from './schemas/cat.schema';
import { CreateCatDto } from './dto/create-cat.dto';

@Injectable()
export class CatsService {
  constructor(@InjectModel(Cat.name) private catModel: Model<CatDocument>) {}

}

 

아직 DTO파일을 안 만들었기 때문에 에러가 뜬다. DTO파일을 작성해보자.

 

$ npm i class-validator class-transformer

 

 

create-cat.dto.ts

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

export class CreateCatDto {
    @IsString()
    readonly name: string;

    @IsNumber()
    readonly age: number;
    
    @IsString({each:true})
    readonly breed: string;
}

 

이제 Contoller를 작성해보자.

 

cat.controller.ts

import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cats.service';
import { Cat } from './schemas/cat.schema';


@Controller('cats')
export class CatsController {
    constructor(private readonly catsService: CatsService) {}

}

 

여기까지 cats모듈과 dto를 만들어보았다.

 

728x90
반응형

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

Nest.js | MongoDB | Create  (0) 2021.10.06
Nest.js | MongoDB | Find  (0) 2021.10.06
Nest.js | MongoDB | Schema  (0) 2021.10.06
Nest.js | E2E TESTING | PATCH and DELETE  (0) 2021.09.30
Nest.js | E2E TESTING | Testing GET movies id  (0) 2021.09.30
728x90
반응형

이 글은 NestJS document 사이트 기반으로 작성했습니다.

 

https://docs.nestjs.kr/techniques/mongodb

 

네스트JS 한국어 매뉴얼 사이트

네스트JS 한국, 네스트JS Korea 한국어 매뉴얼

docs.nestjs.kr

 

몽고DB설치하는 법은 아래 링크에서 확인 부탁드립니다.

 

https://typo.tistory.com/entry/MongoDB%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0%EC%82%AD%EC%A0%9C%ED%95%98%EA%B8%B0?category=866148

 

MongoDB | 설치하기, 삭제하기

1.    몽고DB의 public GPG key 주입 ubuntu@dev:~$ wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add - OK 2.    몽고DB를 위한 리스트 파일 생성 ubuntu@dev:~$ echo "d..

typo.tistory.com

 

mongoDB가 준비되었다면 이제 mongoose를 프로젝트 폴더에 설치해준다.

$ npm install --save @nestjs/mongoose mongoose

 

 

이제 MongooseModule을 루트 AppModule로 가져올 수 있다. ( id와 패스워드는 각자 설정한대로)

forRoot() 메소드는 Mongoose 패키지의 mongoose.connect()와 동일한 구성 객체를 허용한다.

 

app.module.ts

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [MongooseModule.forRoot('mongodb://test:test1234@localhost:27017/admin')],
})
export class AppModule {}

 

Mongoose에서는 모든 것이 스키마에서 파생된다. 스키마는 모델을 정의하는 데 사용된다.

schemas 폴더를 만들고 cat.schema.ts 파일을 작성해보자.

 

/src/cat/schemas/cat.schema.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type CatDocument = Cat & Document;

@Schema()
export class Cat {
  @Prop()
  id: number;

  @Prop()
  name: string;

  @Prop()
  age: number;

  @Prop()
  breed: string;
}

export const CatSchema = SchemaFactory.createForClass(Cat);

 

@Props() 데코레이터는 문서의 속성을 정의한다. 예를 들어 다음과 같이 정의할 수 있다.

@Prop([String])
tags: string[];

 

또는 사용 가능한 옵션에 대한 옵션 객체 인수를 받는다. 기본값을 지정하거나 속성이 필요한지 여부를 나타낼 수 있다.

@Prop({ required: true })
name: string;

 

또는 데코레이터를 사용하지 않음을 선호하는 경우 스키마를 수동으로 정의할 수 있다.

export const CatSchema = new mongoose.Schema({
  name: String,
  age: Number,
  breed: String,
});

 

 

728x90
반응형
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
반응형

+ Recent posts