<TIL-typescript> Layered-Architecture, class-validator, class-transfer

화성농부·2020년 3월 20일
0
post-thumbnail

간단한 인스타그램을 모방한 웹앱을 만들고 있다.
프론트에서는 타입스크립트 뷰 를 만들었고, 백엔드작업에서는 typescript+express 로 개발중이다.
서버개발캠프 4기 활동중에 타입스크립트를 좋게 썼던 경험으로 typescript를 이용해서 견고하고 꼼곰하게 설계를 해보는게 목표다!
인증+멤버십 서버를 설계하던중, 이전까지는 Layered-Architecture에 별로 신경을 쓰지 못했다. 이번에는 3계층으로 서버를 설계하기로 했다.

프로젝트 디렉토리 구조

src
└──app.ts		# App class 정의
└──server.ts		# App entry point  
└──config/		# 환경변수나 각 종 configuration을 수행하는 클래스들 정의
└──controllers/		# 라우팅에 해당하는 클래스들을 정의
└──dtos/		# 컨트롤러에서 서비스간 데이터 교환을 위한 DTO 클래스들 정의
└──entities/		# typeORM DAO 클래스들 정의
└──exceptions/		# 에러핸들링 처리를 위한 클래스들 정의
└──interfaces/		# 각종 인터페이스들 정의
└──middlewares/		# validate, auth 등의 미들웨어 정의
└──routes/		# 라우팅 클래스들을 정의
└──services/		# 비지니스 로직을 위한 서비스 클래스들 정의

알고있는 지식으로 최대한 잘 설계해보려고 디렉토리 구조를 나누었다.
처음으로 계층을 3개로 나누고, 의존성도 신경쓰려다보니 처음에는 코딩할때 많이 어색했던것 같다.
그래도 스켈레톤을 먼저 작성하고 코딩하다보니 익숙해진것 같다.

이해를 위한 간단한 시뮬레이션

  1. route 클래스로 요청이 들어온다
  2. route의 path에 따라 controller 클래스가 실행
  3. controller를 통해 service가 실행되기전 middleware를 통해 요청 데이터들을 validate
  4. service는 controller 에게 dto를 전달 받고 비지니스 로직을 실행
  5. service는 db 요청이 필요할때, ORM을 통해(DAO) db서버와 통신함
  6. service는 controller 에게 요청한 서비스의 dto를 리턴
  7. controller는 리턴받은 dto를 유저에게 전송

class-validator, class-transfer

import { IsEmail, IsString } from 'class-validator';
class CreateUsersDto {
  @IsEmail()
  public email : string;

  @IsString()
  public nickname : string;

  @IsString()
  public pw : string;
}

class-validate 같은 경우에는 데코레이터와 비 데코레이터를 통해서 validate를 수행할 수 있다.

import { plainToClass } from 'class-transformer';
import { validate, ValidationError } from 'class-validator';
import { RequestHandler } from 'express';
import HttpException from '../exceptions/HttpException';

function validationMiddleware(type: any, skipMissingProperties = false): RequestHandler {
  return (req, res, next) => {
    validate(plainToClass(type, req.body), { skipMissingProperties })
    .then((errors: ValidationError[]) => {
      if (errors.length > 0) {
        const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(', ');
        next(new HttpException(400, message));
      } else {
        next();
      }
    });
  };
}

body에 담긴 데이터들을 검증하는 미들웨어이다. type으로 들어오는 오브젝트가 앞서 데코레이터를 통해 정의한 값과 일치하는지 검증한다.

plainToClass

자바스크립트에는 두 종류의 객체가 존재한다.

  • plain(literal) Object: 보통 {} 통해 정의된 오브젝트
  • class(constructor) Object: 클래스를 통해 정의된 오브젝트 , 생성자, 메서드, 프로퍼티 등을 갖는다.

class-transfer에 정의된 plaintToClass 메서드를 통하여 plain object 를 class object로 변경할 수 있다.
객체를 직렬화,역직렬화 하는 이유와 비슷하다고 볼 수 있다. body에 들어온 json 데이터를 다른 클래스와 매핑을 시켜 사용할 수 있기 때문.

Opt?: skipMissingProperties

true로 설정할 경우, null이나 undefined인 속성들을 무시한다.
false의 경우 그 반대

profile
Meyogu@Mars

1개의 댓글

comment-user-thumbnail
2020년 3월 28일

화하

근데 진짜 누구인가~? 서캠인 것만 알겠는데
타입스크립트하면 기장형인 것 같은데

답글 달기