[Clone Coding] What I Learn 4-2 : Custom Guard & Custom Decorator

먹보·2023년 1월 31일
0

MUK_BO's Clone Coding

목록 보기
5/7

✍ <기술 스택>

  • Programming Language
    TypeScript
  • Framework
    NestJS
  • API 설계
    GraphQL and Apollo
  • Database & Relevant
    PostgresQL & TypeORM

USER CRUD를 만들게 되면서 DecoratorGuards에 대해서 조금 더 자세히 다루게 되어 이번 기회에 한 번 파고들어보자 한다.

✍ Decorator

Decorator, 이전 게시글들에서 간혹 언급한 적이 있으며, 실제로 NestJS에서 가장 많이 쓰이는 개념 중 하나이지만 사실 Decorator의 개념은 NestJS에서가 아닌 JavaScript에 있는 문법 중 하나이다.

Decorator는 존재하는 class, method 또는 propery에 새로운 방식을 추가해 프로그래밍 하는 것으로 '@' 심볼을 사용해 적용 할 수있다.

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User) private readonly users: Repository<User>,
    @InjectRepository(Verification)
    private readonly verification: Repository<Verification>,
    private readonly jwtService: JwtService,
  ) {}

상기 예제에서는 @InjectableDecorator이다.

📝 Decorator의 장/단점

✏️ 장점

  1. 재사용성
  2. 가독성? : 사실 장점이자 단점이라고 꼽피는데..개발자 성향에 따라 다른 것 같다.
  3. 관심사 분리
  4. 메타 데이터 : class, method, property에 메타 데이터를 추가로 넣을 수 있다.

✏️ 단점

  1. 복잡성 : Decorator를 추가하는 것만으로 코드를 복잡하게 만들며 디버깅이 힘들어진다.

  2. 추상적 : 사실 Decorator는 겉으로 보기에는 @로 표기하는 것이 전부이기에, 겉만 봐서는 naming convention이 정확하지 않는 이상 파악하기 어렵다.

  3. 호환성 : Decorator는 자바스크립트에서 상대적으로 최근에 만들어진 개념이기에 호환이 안될 수 도 있다.

  4. 성능 : Decorator는 코드 위에 쓰여지기 때문에 규모가 큰 앱 상에서 성능 저하를 일으킬 수 있다
    => 어 잠만? NestJS는 Enterprise급 웹 개발에 적합하다고 되어 있고 Decorator를 Express와 비교했을 때 상당히 많이 쓰이는데...그럽 Express보다 속도가 느리고 Enterprise급 개발에 비적합한 거 아닌가?
    => 찾아보니깐 다음과 같다고 한다..

    NestJS is indeed heavily reliant on decorators, but it's important to note that NestJS is designed for building scalable and maintainable applications, not just small-scale applications. It includes features such as modular architecture, dependency injection, and efficient testing that are essential for building large-scale applications. Additionally, NestJS is built on top of the popular Express.js framework, which provides robust and efficient HTTP request handling capabilities

Decorator는 성능 저하의 주요 원인이 되기에는 미세한 임팩트를 가지고 있고 NestJS에서 제공하는 그 외의 기능들의 강점이 충분히 보완이 되기 때문에 상관 없다.

📝 Custom Decorator 만들기

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';

export const AuthUser = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const gqlContext = GqlExecutionContext.create(ctx).getContext();
    const user = gqlContext['user'];
    return user;
  },
);

상기와 같이 Decorator를 만들고 필요한 구간에 @AuthUser를 붙이면 된다. 아주 간단하죠잉?

✍ Guards

Guards는 단일 역할을 가진 클라스로서 http요청이 들어왔을 때 라우터 들어가기 이전 설정된 조건에 따라 들어온 요청이 정단한 것인지를 판단해 요청에 인가를 결정한다.

📝 Guards의 장/단점

✏️ 장점

  1. 보안성 증가 : Guards의 정의를 보면 알겠지만 http 요청을 한 번 거르는 작업을 하므로 보안에 좋다.
  2. 관심사 분리 : 보안 관련 로직을 Guards로 분리하면서 관심사 분리가 적절히 일어난다.
  3. 재사용성 증가
  4. 유지 보수 : 보안 관련 로직을 캡슐화 하는 것으로 유지 관리가 용이해진다.

✏️ 단점

  1. 오버헤드
  2. 코드의 가독성(?)
  3. 성능 저하(미세하다고 한다).

✏️ 일반적인 Middleware와의 차이점

사실 Middleware를 조금 더 큰 집합이라고 생각하면 된다.

물론 Middleware와 Guards의 사용 목적이 엄연히 다르겠지만 Middleware를 가드 처럼 구현하면 Guards 역할을 사용할 수 있다.

하지만 Guards가 Authorization에 더욱 적합하므로 Authorization에는 Guards를 적용하는 것이 더 적합해 보인다.

📝 Custom Guards 만들기

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const gqlContext = GqlExecutionContext.create(context).getContext();
    const user = gqlContext.user;
    if (!user) {
      return false;
    }
    return true;
  }
}

CanActivate Interface를 적용하여 Guards를 만든 후 원하는 위치에 @UseGuards(AuthGuard)를 적용해주면 간단하다!

profile
🍖먹은 만큼 성장하는 개발자👩‍💻

0개의 댓글