[Nest.JS] @UseInterceptors와 @Expose/@Exclude로 직렬화 최적화하기

궁금하면 500원·2024년 8월 11일
0
post-thumbnail

1. NestJS의 @UseInterceptors에 대해

@UseInterceptors는 NestJS에서 제공하는 데코레이터로, 인터셉터(Interceptor)를 지정할 때 사용됩니다.

인터셉터는 NestJS의 미들웨어와 유사하지만, 더욱 강력하고 다양한 기능을 제공하며,
요청(request)과 응답(response) 사이에서 특정 작업을 수행할 수 있습니다.

주요 기능

요청 변환: 요청 데이터를 변환하거나 가공할 수 있습니다.
응답 변환: 응답 데이터를 변환하거나 수정할 수 있습니다.
로그 작성: 요청과 응답을 기록하거나 로그 데이터를 추가할 수 있습니다.
캐싱 처리: 응답 데이터를 캐시 처리할 수 있습니다.
비동기 작업 처리: 요청이 완료되기 전에 특정 비동기 작업을 수행할 수 있습니다.

기본사용법

import { UseInterceptors, Controller, Get } from '@nestjs/common';
import { LoggingInterceptor } from './logging.interceptor';

@Controller('users')
@UseInterceptors(LoggingInterceptor) // 클래스 수준에서 인터셉터 적용
export class UserController {
    @Get()
    findAll() {
        return 'This action returns all users';
    }
}

메서드 수준 적용

import { UseInterceptors, Controller, Get } from '@nestjs/common';
import { LoggingInterceptor } from './logging.interceptor';

@Controller('users')
export class UserController {
    @Get()
    @UseInterceptors(LoggingInterceptor) // 메서드 수준에서 인터셉터 적용
    findAll() {
        return 'This action returns all users';
    }
}

인터셉터 구현 예시

인터셉터는 NestInterceptor 인터페이스를 구현하여 만듭니다.

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        console.log('Before...');

        const now = Date.now();
        return next
            .handle()
            .pipe(
                tap(() => console.log(`After... ${Date.now() - now}ms`)),
            );
    }
}

이 인터셉터는 요청이 들어왔을 때 "Before..." 메시지를 출력하고, 응답이 완료되었을 때 "After..." 메시지를 출력합니다.

그리고 요청이 처리되는 시간을 측정하는 역할을 합니다.

Interceptors의 흐름

  1. 클라이언트가 요청을 보냅니다.
  2. 요청이 컨트롤러에 도달하기 전에 인터셉터가 실행됩니다.
  3. 요청이 컨트롤러로 전달되기 전에 인터셉터가 데이터를 수정할 수 있습니다.
  4. 컨트롤러가 응답을 반환하면, 인터셉터가 다시 실행되어 응답 데이터를 수정하거나 추가 작업을 할 수 있습니다.
  5. 클라이언트가 응답을 받습니다.

2. NestJS의 @Expose와 @Exclude에 대해

@Expose@Excludeclass-transformer 라이브러리에서 제공하는 데코레이터로, NestJS에서 DTO(Data Transfer Object) 변환 시 자주 사용됩니다.

이 두 데코레이터는 객체의 직렬화 및 역직렬화 과정에서 특정 속성을 포함하거나 제외하는 데 사용됩니다.

@Expose

@Expose()는 특정 속성을 직렬화 시 명시적으로 포함시키고자 할 때 사용됩니다.

기본적으로 직렬화 과정에서 모든 속성이 포함되지만, @Exclude()로 제외된 속성이나, 직렬화 과정에서 특별히 다루고 싶은 속성을 명시적으로 선언할 때 사용합니다.

import { Expose } from 'class-transformer';

class User {
    @Expose() // 이 필드는 직렬화될 때 포함됨
    id: number;

    @Expose()
    name: string;

    password: string; // 직렬화에서 자동으로 제외됨
}

const user = new User();
user.id = 1;
user.name = 'John Doe';
user.password = '123456';

console.log(JSON.stringify(user));
// 출력 결과: {"id":1,"name":"John Doe"}

@Exclude

@Exclude()는 특정 속성을 직렬화 시 제외할 때 사용됩니다.
이 데코레이터는 해당 속성을 plain object로 변환할 때 포함되지 않도록 합니다.

import { Exclude } from 'class-transformer';

class User {
    id: number;

    @Exclude() // 이 필드는 직렬화될 때 제외됨
    password: string;

    name: string;
}

const user = new User();
user.id = 1;
user.password = '123456';
user.name = 'John Doe';

console.log(JSON.stringify(user));
// 출력 결과: {"id":1,"name":"John Doe"}

함께 사용 예시

@Expose@Exclude는 함께 사용할 수 있습니다.

특정 속성은 제외하고, 다른 속성은 포함하는 방식으로 데이터를 유연하게 직렬화/역직렬화할 수 있습니다.

import { Exclude, Expose } from 'class-transformer';

class User {
    @Exclude() // 직렬화에서 제외
    password: string;

    @Expose({ name: 'fullName' }) // 'name' 속성을 'fullName'으로 변환하여 포함
    name: string;

    id: number;
}

const user = new User();
user.id = 1;
user.password = '123456';
user.name = 'John Doe';

const plainUser = classToPlain(user);
console.log(plainUser);
// 출력 결과: {"fullName":"John Doe","id":1}

결론

  • @UseInterceptors: 인터셉터를 사용하여 요청과 응답 사이에 추가 로직을 실행할 수 있습니다.

  • @Expose: 특정 필드를 직렬화 과정에서 명시적으로 포함시킵니다.

  • @Exclude: 특정 필드를 직렬화 과정에서 제외시킵니다.

profile
꾸준히, 의미있는 사이드 프로젝트 경험과 문제해결 과정을 기록하기 위한 공간입니다.

0개의 댓글