본문 바로가기

반환 정보 편집하기

@정소민fan2025. 6. 15. 23:02

지금까지의 포스팅에서는 엔티티 자체를 json으로 바꿔서 모든 정보를 반환해줬다.

하지만 스프링을 한창 배울 때 절대로 엔티티의 정보를 전부 그대로 보여주지 말라고 했던 기억이 난다.

예를 들어 User 엔티티에 password 필드가 있으면 이건 넘기면 안되니까

그러면 어떻게 원하는 필드만 편집해서 넘길 수 있는건가

인터셉터와 데코레이터 사용

먼저 반환할 엔티티의 숨기고 싶은 필드에 다음과 같이 @Exclude 데코레이터를 추가한다.

@Entity()
export class User {
...
    @Column()
    @Exclude() // 여기 추가
    password: string;
...
}

그 다음 이 엔티티를 반환하는 컨트롤러에서 다음과 같이 사용해주자

컨트롤러에 달아주면 모든 라우트 핸들러에 적용될 것이고, 특정 라우트 핸들러에만 달아준다면 그 경로에 들어갈 때만 적용될 것이다

@UseInterceptors(ClassSerializerInterceptor) // 여기 추가
@Controller('auth')
export class UsersController {
...
  @Get()
  findAllUsers(@Query('email') email: string) {
    return this.usersService.find(email);
  }
...
}

인터셉터는 요청이나 응답을 가로채 특정 로직을 수행한 뒤, 그 결과를 반환하는 중간 처리 모듈이다.

 

GPT
ClassSerializerInterceptor는 NestJS에서 응답 객체를 직렬화(serialize)할 때 사용되는 내장 인터셉터
즉, 컨트롤러에서 반환한 객체를 JSON으로 변환하는 과정에서 일부 필드를 숨기거나 가공할 수 있게 해주는 도구

뭐 그렇다고 하네

응답 DTO 사용

또 다른 방법은 응답 DTO를 따로 만들어서 사용하는 것이다.

위에서의 방법은 엔티티의 있는 내용에서만 한정해서 응답을 줄수밖에 없다는 단점이 있다.

예를 들어 User에는 id, email, password 정보밖에 없지만, 이 유저가 작성한 post의 갯수도 필요할 때, 어떻게 이 정보를 같이 가공해서 넘겨줄 것인가? 두 개 이상의 리포지토리에서 정보를 가져와서 하나의 서비스에서 그 정보를 합쳐 컨트롤러에 넘겨준 다음, 컨트롤러에서 직렬화를 수행해서 보내는 것이 가장 이상적일 것이다.

DTO 만들기

import { Expose } from 'class-transformer';

export class UserDto {

  @Expose()
  id:number

  @Expose()
  email:string
}

기존의 User 엔티티에서 id와 email만 응답으로 보내고 싶다면 이렇게 UserDto를 만들자

@Expose()는 외부에 공개할 필드이다

인터셉터 만들기

export function Serialize(dto:any) {
  return UseInterceptors(new SerializeInterceptors(dto));
}

export class SerializeInterceptors implements NestInterceptor{

  constructor(private dto: any) {
  }

  intercept(context: ExecutionContext, next: CallHandler<any>): Observable<any> {
    return next.handle().pipe(
      map((data:any) => {
        return plainToInstance(this.dto, data, {
          excludeExtraneousValues: true,
        })
      })
    );
  }
}

이 인터셉터는 직렬화에 사용될 dto를 생성자에서 인자로 받고 있다.

interceptor 메소드에서 return문 내의 map의 plainToInstance로 data (원래 보내야 할 응답, UserEntity)를 인자로 받은 dto로 커스텀해서 리턴해준다

excludeExtraneousValues를 true로 설정해 놓으면 dto에서 @Expose() 데코레이터가 달려있는 필드만 직렬화한다.

 

코드 맨 위에서는 export function Serialize를 통해 이 데코레이터를 단순하게 사용할 수 있도록 도와주고 있다.

컨트롤러에서 @Serialize(dto)만 달아놓으면 @UseInterceptor(new SerializeInterceptors(dto) 를 사용한 것과 같은 효과가 난다. 그냥 치환해주는거라고 보면 된다.

@Controller('auth')
@Serialize(UserDto)
export class UsersController {
...
}

이렇게 컨트롤러에서도 사용 가능하고, 라우트 핸들러에서도 사용 가능하다.

인자 타입 제한하기

지금은 any타입으로 어떤 인자이든 들어올 수 있다. 이는 @Serialize("im string")과 같은 말도 안되는 인자도 들어올수 있고, 이를 컴파일 시점에 잡아내지 못하고 런타임 시점에서 오류가 터질수 있다는 소리이다.

이를 막으려고 타입스크립트 쓰는거 아닌가?

/* 추가 */
interface ClassConstructor {
  new (...args: any[]): {};
}

export function Serialize(dto:ClassConstructor) { // 수정
  return UseInterceptors(new SerializeInterceptors(dto));
}

이렇게 사용하면 일단은 Class 만 인자로 들어올수 있도록 강제할 수 있다. 좀더 상세한 타입으로 강제할 수도 있다고 한다.

'NestJS' 카테고리의 다른 글

NestJS + Qdrant 사용해보자 !!  (6) 2025.08.08
AWS bedrock 사용기  (5) 2025.08.05
입력 정보 검증하기  (0) 2025.06.15
TypeORM 간단 사용법  (0) 2025.06.15
제어 역전 / 의존성 주입  (0) 2025.06.14
정소민fan
@정소민fan :: 코딩은 관성이야

코딩은 관성적으로 해야합니다 즐거운 코딩 되세요

목차