nestjs - nestia와 비교

00_8_3·2023년 5월 30일
0

nestjs

목록 보기
1/3

사전지식

  • nestia란 nest helper 라이브러리이다.

  • 데코레이터는 @Decorator 와 같이 작성을 하며
    보통 reflect-metadata를 라이브러리를 사용하여 class를 리플렉션한다.

  • typia는 class-validator와 같은 런타임 타입 검증 라이브러리이다.

라우터 핸들러

nestjs

  • packages/common/decorators/http/request-mapping.decorator.ts
const createMappingDecorator: (method: RequestMethod) => (path?: string | string[]) => MethodDecorator

nestia

  • packages/core/src/decorators/TypedRoute.ts
function Generator(method: "Get" | "Post" | "Put" | "Patch" | "Delete"): {
    (path?: string | string[]): MethodDecorator;
    <T>(stringify?: IResponseBodyStringifier<T> | undefined): MethodDecorator;
    <T>(path: string | string[], stringify?: IResponseBodyStringifier<T> | undefined): MethodDecorator;
}
  • 타입스크립트 내장 타입인 MethodDecorator를 반환한다.

  • nestjs/common의 메소드 데코레이터를 인터셉터로 감싸고 applyDecorators로 감싼다.

applyDecorators는 파라미터로 받은 데코레이터 배열을 모두 적용한 하나의 데코레이터를 반환한다.
여러 데코레이터를 캡슐화하는 경우 유용하다.

UseInterceptors는 컨텍스트에 따라 인터셉터를 컨트롤러 또는 메서드의 범위에 바인딩하는 데코레이터입니다.
컨트롤러 수준에서 @UseInterceptors를 사용하면 컨트롤러의 모든 핸들러(메서드)에 인터셉터가 적용됩니다.
개별 핸들러 수준에서 @UseInterceptors를 사용하면 인터셉터가 해당 특정 메서드에만 적용됩니다.

https://docs.nestjs.com/interceptors
https://docs.nestjs.com/interceptors#binding-interceptors

차이점

const take =
    (method: string) =>
    <T>(functor?: IResponseBodyStringifier<T> | null) => {
        if (functor === undefined) throw TransformError(method);
        else if (functor === null) return JSON.stringify;
        else if (functor.type === "stringify") return functor.stringify;
        else if (functor.type === "assert") return assert(functor.assert);
        else if (functor.type === "is") return is(functor.is);
        else if (functor.type === "validate") return validate(functor.validate);
        throw new Error(
            `Error on nestia.core.${method}(): invalid typed stringify function.`,
        );
    };
  • 기본적인 nestjs의 내장 라우터 데코레이터는 동일.

  • nestia의 내장인 typia의 assert, is, validate를 사용한다.

tip

const validate =
    <T>(closure: (data: T) => IValidation<string>) =>
    (data: T) => {
        const result: IValidation<string> = closure(data);
        if (result.success === false)
            throw new InternalServerErrorException({
                errors: result.errors,
                message: MESSAGE,
            });
        return result.data;
    };

typia를 사용해본 유저라면 알겠지만 메소드를 직접 사용하면 되는데
함수(closure)로 감싸 사용하는 모습에 의아할 수 있다.

왜 그러하냐면 타입스크립트는 컴파일 언어인데

nestia(typia)에서는 AOT를 사용해서 TS 타입검증을 JS트랜스파일 하기 때문이다.

export type CreatePostBody = {
    title: string;
};

const validateBody = <T>(x: unknown) => {
    return TSON.validateEquals<T>(x);
};

const body = {
    title: "this is title"
};

validateBody<CreatePostBody>(body);

예를들어 위와 같은 코드는 컴파일 타임에 에러가 발생하지 않지만 nestia의 AOT과정(빌드)에서 에러를 일으킨다. 왜냐하면 제네릭 T가 런타임에는 사라지기 때문에 알수 없다는 것 알기 때문이다.

그래서 typia에서는 createValiteEquals와 같은 런타임에도 사용할수 있도록
Reusable functions를 제공하는데 위의 클로져가 이놈이다.

0개의 댓글