NestJS 에  있는 "ValidationPipe" 를 이용하면 유효성 검사를 할 수 있다.

 

"ValidationPipe" 를 이용하기 위해서 아래 두개의 라이브러리를 설치해야한다.

$ npm i --save class-validator class-transformer

 

자동으로 적용하기 위해 main.ts 에 아래와 같이 입력

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

async function bootstrap() {
  initializeTransactionalContext(); // Transactional 을 이용하기 위해 선언
  const app = await NestFactory.create(AppModule);
  // 자동으로 validation을 확인하기 위해 선언
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true, //class-transform 을 사용하기위한 설정
    }),
  );
  await app.listen(3000);
}
bootstrap();

 

 

- option 설명

app.useGlobalPipes(new ValidationPipe({
    whitelist: true,  // 미리 정의되지 않은 필드를 자동으로 제거합니다.
    transform: true,  // 클라이언트로부터 받은 데이터를 DTO 인스턴스로 자동 변환합니다.
    forbidNonWhitelisted: true,  // DTO에 정의되지 않은 필드가 포함되어 있을 경우 요청을 거부합니다.
    disableErrorMessages: false,  // 개발 중 오류 메시지를 표시하여 디버깅을 도움니다.
  }));

 

다음으로 Entity에 설정하여 유효성 테스트하는 방법

예시 1

import { validate, validateOrReject, Contains, Length,} from 'class-validator';
import { PrimaryGeneratedColumn, Column} from 'typeorm' 
import { Transactional } from 'typeorm-transactional';
import { plainToClass } from 'class-transformer';

// entity
export class Board {
  @PrimaryGeneratedColumn()
  id: number;
  
  @Length(10, 20)
  @Column
  title: string;

  @Contains('hello')
  @Column
  text: string;
}

// dto
export class CreatePostRequestDto{
  title: string;
  text: string;
}

@Transactional()
async create(createPostRequestDto: CreatePostRequestDto) {

    const newPost = plainToClass(Board, createPostRequestDto); // transformer 이용

    const postValidation = await validate(newPost); //validation 확인
    if (postValidation.length > 0) {
      throw new BadRequestException(`validation failed. errors: ${postValidation}`);
    }
 }

 

입력예시

createPostRequestDto = {
   title: "hi",
   text: "validation test"
}

 

에러출력 

{
    "message": "validation failed. errors: An instance of Board has failed the validation:\n - property title has failed the following constraints: isLength \n",
    "error": "Bad Request",
    "statusCode": 400
}

 

예시 2 : Dto 에 제약을 설정

....

export CreatePostRequestDto{
  @Length(10, 20) // 추가
  title: string;
  
  text: string;
}

@Transactional()
  async create(createPostRequestDto: CreatePostRequestDto) {

    ....

 }

 

같은 입력을 주면 아래에 따로 validation을 확인 할 필요없이 에러문구가 아래와 같이 뜬다.

{
    "message": [
        "title must be longer than or equal to 5 characters"
    ],
    "error": "Bad Request",
    "statusCode": 400
}

 

 

참고자료

https://docs.nestjs.com/techniques/validation

 

Built in HTTP Exception (NestJS) HTTP Status code 의미
BadRequestException 400 Bad Request 서버가 클라이언트 오류(예: 잘못된 요청 구문, 유효하지 않은 요청 메시지 프레이밍, 또는 변조된 요청 라우팅) 를 감지해 요청을 처리할 수 없거나, 하지 않는다는 것을 의미
NotFoundException 404 Not Found 클라이언트 오류 응답 코드는 서버가 요청받은 리소스를 찾을 수 없다는 것을 의미
리소스가 영구적으로 삭제되었다면 404 상태 코드 대신 
410 (Gone) 상태 코드가 쓰여야 합니다.
ConflictException 409 Conflict 서버에서 요청이 유효하지만, 해당 요청을 처리함으로써 리소스의 현재 상태와 충돌이 발생했음을 나타냅니다.
UnauthorizedException
401 Unauthorized 요청된 리소스에 대한 유효한 인증 자격 증명이 없기 때문에 클라이언트 요청이 완료되지 않았음을 나타냅니다
     

 

참고자료

MDN web doc : https://developer.mozilla.org/ko/docs/Web/HTTP/Status/200

종류 : https://docs.nestjs.com/exception-filters#built-in-http-exceptions

  • ForbiddenException
  • NotAcceptableException
  • RequestTimeoutException
  • GoneException
  • HttpVersionNotSupportedException
  • PayloadTooLargeException
  • UnsupportedMediaTypeException
  • UnprocessableEntityException
  • InternalServerErrorException
  • NotImplementedException
  • ImATeapotException
  • MethodNotAllowedException
  • BadGatewayException
  • ServiceUnavailableException
  • GatewayTimeoutException
  • PreconditionFailedException

 

board.service.ts 에서 아래와 같이 다른 서비스를 이용하려니까 발생한 문제

@Injectable()
export class BoardService {
  constructor(
    private readonly hashtagService: HashtagService,
    private readonly categoryService: CategoryService,
    private readonly boardToCategoryService: BoardToCategoryService,
    private readonly hashtagToBoardService: HashtagToBoardService,
    @InjectRepository(Board)
    private readonly boardRepository: Repository<Board>,
  ) {}

 

 

에러문구

 ERROR [ExceptionHandler] Nest can't resolve dependencies of the BoardService (HashtagService, CategoryService, ?, HashtagToBoardService, BoardRepository). Please make sure that the argument BoardToCategoryService at index [2] is available in the BoardModule context.

Potential solutions:
- Is BoardModule a valid NestJS module?
- If BoardToCategoryService is a provider, is it part of the current BoardModule?
- If BoardToCategoryService is exported from a separate @Module, is that module imported within BoardModule?
  @Module({
    imports: [ /* the Module containing BoardToCategoryService */ ]
  })

 

 

해결방식

1. 오류내용을 확인 -> 잘 이해가 안된다.

2. 오류메세지를 구글링 -> module의 imports 부분에 추가를 해주거나 중복된것이 있는지 확인해야 한다고함.

3. 다시 오류메시지 확인

->  솔류션에 적혀있는 대로 내가 사용하려는 서비스가 BoardModule의 일부분이 아니였다.

 

오류 코드

import { BoardController } from './board.controller';
import { BoardService } from './board.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Board } from '../../entities/Board.entity';

@Module({
  imports: [
    TypeOrmModule.forFeature([Board]),
  ],
  controllers: [BoardController],
  providers: [BoardService],
})
export class BoardModule {}

 

해결한 코드

import { BoardController } from './board.controller';
import { BoardService } from './board.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Board } from '../../entities/Board.entity';
import { HashtagModule } from '../hashtag/hashtag.module';
import { HashtagToBoardModule } from '../hashtag_board/hashtagToBoard.module';
import { BoardToCategoryModule } from '../board_category/boardToCategory.module';
import { CategoryModule } from '../category/category.module';

@Module({
  imports: [
    TypeOrmModule.forFeature([Board]),
    CategoryModule,
    HashtagModule,
    BoardToCategoryModule,
    HashtagToBoardModule,
  ],
  controllers: [BoardController],
  providers: [BoardService],
  exports: [BoardService],
})
export class BoardModule {}

 

< 추가로 설정해야하는 부분 >

imports 한 각 module에 내가 사용할 service를 exports 해줘야한다.

예시

import { Module } from '@nestjs/common';
import { ReplyController } from './reply.controller';
import { ReplyService } from './reply.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Reply } from '../../entities/entity.index';

@Module({
  imports: [TypeOrmModule.forFeature([Reply])],
  controllers: [ReplyController],
  providers: [ReplyService],
  exports: [ReplyService], // <--- 이 부분을 써줘야 다른 곳에서 서비스 사용가능
})
export class ReplyModule {}

 

 

마치 app.module.ts 에서 내가 만든 서비스를 사용하기 위해서 다른 모듈을 다 imports에 넣듯이

여기서도 같은 원리로 내가 원하는 서비스를 포함하는 모듈을 imports에 넣으면 되는 것이였다.

설치한 라이브러리

https://www.npmjs.com/package/typeorm-snake-naming-strategy

 

typeorm-snake-naming-strategy

Snake naming strategy for TypeORM.. Latest version: 1.0.2, last published: 4 years ago. Start using typeorm-snake-naming-strategy in your project by running `npm i typeorm-snake-naming-strategy`. There is 1 other project in the npm registry using typeorm-s

www.npmjs.com

 

상황:

TypeORM 에서 snakeCase 로 자동으로 바꿔주는 라이브러리를 설치했는데 위와 같은 에러가 뜸

 

이유:

ES 버전이 맞지 않아서 생기는 오류

 

문제

이것 때문에 setting에서 ES 버전도 바꾸어보고 했는데 

결국, 위에서 설치한 라이브러리가 너무 오래 된것이다.... 

 

최신버전으로 배포된 아래 라이브러리를 설치 하니 바로 해결된다... 라이브러리 이름이 너무 똑같다;;;;

https://www.npmjs.com/package/typeorm-naming-strategies

 

typeorm-naming-strategies

Custom naming strategies for typeorm. Latest version: 4.1.0, last published: 2 years ago. Start using typeorm-naming-strategies in your project by running `npm i typeorm-naming-strategies`. There are 98 other projects in the npm registry using typeorm-nami

www.npmjs.com

 

 

라이브러리는 항상 최신버전으로!!!

공개된지 너무 오래된 것이 있으면 한번 의심해보고 최신버전이 있는지 찾아보자

 

1 : N

Board : Reply

Board : HashToBoard

Board : BoardToCategory

 

Hashtag : HashToBoard

Category : BoardToCategory

 

 

N : M

Board : Hashtag

Board : Category

 

연결다리

BoardToCategory

HashToBoard

 

 

DB에 연결된 ERD ( entity relation diagram)

+ Recent posts