**직렬화(serialization)**는 객체가 응답으로 전송되는 JSON으로 어떻게 변환되는지 제어합니다 — 결정적으로 민감한 필드 제외(비밀번호 같은)와 출력 형태 지정입니다. NestJS는 ClassSerializerInterceptor와 class-transformer decorator로 이를 처리합니다.
문제: 민감한 데이터 누출
()
() {
..(id);
}
데이터베이스 entity를 직접 반환하면 클라이언트에 절대 도달해서는 안 되는 필드(비밀번호 해시, 내부 플래그, 토큰)를 노출할 수 있습니다 — 심각한 보안/프라이버시 문제입니다.
import { Exclude } from "class-transformer";
export class User {
id: number;
name: string;
email: string;
@Exclude() // 이 필드는 응답에서 제거됨
password: string;
}
// serializer interceptor 활성화 (전역 또는 controller별)
@UseInterceptors(ClassSerializerInterceptor)
@Controller("users")
export class UsersController {
@Get(":id")
findOne(@Param("id") id): User {
return this.usersService.findOne(id); // 비밀번호가 자동으로 제거됨
}
}
// 또는 전역: app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)))
ClassSerializerInterceptor는 응답을 직렬화할 때 class-transformer decorator를 적용하므로, @Exclude() 필드가 자동으로 제거됩니다 — 단, 클래스 인스턴스를 반환하는 경우에만(일반 객체가 아님).
export class User {
@Expose() id: number; // 명시적으로 포함 (excludeAll 전략과 함께)
@Exclude() password: string; // 출력에서 제거
@Expose({ name: "full_name" }) // 출력에서 이름 변경
name: string;
@Transform(({ value }) => value.toUpperCase()) // 값 변환
code: string;
@Exclude({ toPlainOnly: true }) // 직렬화 OUT 시에만 제외 (입력 시에는 아님)
internalField: string;
}
// ⚠️ interceptor는 클래스 인스턴스만 변환 — 일반 객체는 변경 없이 통과
return new User(data); // ✅ decorator 적용됨
return plainToInstance(User, data); // ✅ 일반 객체를 인스턴스로 변환
return { ...data }; // ❌ 일반 객체 — @Exclude가 무시됨!
흔한 함정: 직렬화 decorator는 실제 클래스 인스턴스에서만 작동하므로, 인스턴스를 반환해야 합니다(ORM entity는 보통 인스턴스; 수동으로 만든 일반 객체는 변환 필요).
entity를 데코레이트하는 대신, 클라이언트를 위한 필드만 담은 별도의 Response DTO로
매핑하세요 — 명시적이고, DB 모델과 분리되며, 매우 안전합니다.
응답 직렬화 제어는 보안과 깔끔한 API 설계 모두에 중요합니다.
가장 결정적인 이유는 민감한 데이터 누출 방지입니다 — 데이터베이스 entity를 직접 반환하면 비밀번호 해시, 내부 필드, 토큰, 또는 클라이언트에 절대 도달해서는 안 되는 기타 데이터를 노출할 수 있으며, 이는 흔하고 심각한 취약점입니다.
NestJS의 ClassSerializerInterceptor와 class-transformer decorator(@Exclude, @Expose, @Transform)는 응답 형태를 지정하는 깔끔하고 선언적인 방법을 제공합니다 — 제외된 필드를 자동으로 제거하고, 이름을 변경하고, 값을 변환합니다.
이를 이해하는 것은 사용자나 도메인 데이터를 반환하는 모든 API에 필수적인 일상 지식이며, 핵심 함정 — 직렬화가 일반 객체가 아니라 클래스 인스턴스에서만 작동한다는 것("왜 비밀번호가 아직도 보이지?" 버그의 빈번한 원인) — 을 아는 것은 실무적으로 중요합니다.
마찬가지로 가치 있는 것은 전용 응답 DTO 패턴(entity를 클라이언트에 안전한 필드만 담은 명시적 출력 클래스로 매핑)을 인식하는 것으로, 이는 API 계약을 데이터베이스 모델과 분리하며 민감한 데이터에 가장 안전한 접근입니다.
직렬화를 적절히 제어하는 것은 안전하고 잘 설계된 NestJS API의 특징이며 공개되지 않은 데이터를 다루는 실제 애플리케이션에서 자주 관련되는 관심사입니다.