인터셉터의 역할
인터셉터는 라우팅 실행 전과 실행 후 모두에 작업을 추가할 수 있습니다.
인터셉터가 할 수 있는 일들
메서드 실행 전후에 작업을 추가할 수 있습니다.
함수에서 반환된 결과를 변환할 수 있습니다.
함수에서 발생한 예외를 변환할 수 있습니다.
조건에 따라 함수를 재정의 할 수 있습니다.
인터셉터 구현
인터셉터는 NestInterceptor 인터페이스를 구현해야 합니다.
NestInterceptor 구현 시 intercept(context: ExcutionCentext, next: CallHandler) 메서드를 구현해야 합니다.
매개변수 context는 요청 정보를 담고 있습니다.
매개변수 next는 라우터 핸들러의 참조입니다.
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
import { map, Observable } from 'rxjs';
export class SerializeInterceptor implements NestInterceptor {
intercept(
context: ExecutionContext,
next: CallHandler<any>,
): Observable<any> | Promise<Observable<any>> {
console.log('라우팅 핸들러 실행 전');
return next.handle().pipe(
map((data: any) => {
console.log('라우팅 핸들러 실행 후');
}),
);
}
}
인터셉터 적용
전역 적용
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new LoggingInterceptor());
컨트롤러 혹은 메서드 적용
@UseInterceptors(new LoggingInterceptor())
export class CatsController {}
데이터 직렬화
데이터 직렬화는 데이터를 통신에 사용하기 위한 형태로 변환하는 과정입니다.
데이터 직렬화 직전에 클라이언트에 반환할 데이터가 결정되기 때문에 응답 데이터의 일부를 제외 혹은 수정 하기에 적절한 시점입니다.
예를 들어, 비밀번호 같은 데이터는 응답에서 제외해야 합니다. 또는 Date() 객체를 사용자의 국적 또는 위치에 맞게 변환해야 합니다.
데이터 직렬화는 두 가지 방법이 있습니다.
- ORM의 Model 이용
- DTO 이용
NestJS 문서에는 모델을 이용을 권장합니다. 하지만 하나의 모델은 여러 라우팅에서 사용되고, 라우팅에 따라 직렬화 하는 것이 불가능하기 때문에 권장하지 않습니다.
class-transformer 라이브러리 추가
데이터 직렬화 시 class-transformer 라이브러리를 사용합니다.
npm install class-transformer
@Transform() 데코레이터
데코레이터에 콜백 함수를 전달해 사용합니다.
입력된 데이터를 콜백 함수의 반환값으로 수정합니다.
콜백 함수의 파라미터 선언부에 객체를 전달한 이유는 콜백 함수에 실제로 객체가 전달되기 때문입니다.
value 말고는 사용할 것 같지는 않지만 정리해둡니다.
| 속성 | 설명 |
| value | 값 |
| key | 키 |
| obj | 값이 담긴 객체 전체 |
| type | 변형 유형 |
| options | 콜백 함수에서 사용할 수 있는 옵션 객체 |
import { Transform } from 'class-transformer';
export class Post {
id: number;
@Transform(({ value }) => trim(value) )
title: string;
@Transform(({ value }) => trim(value) )
content: string;
}
class-transformer의 다른 데코레이터
| 데코레이터 | 설명 |
| @Type( () => 자료형 ) | 원래 자료형을 익명함수에서 반환한 자료형으로 변경. 타입스크립트가 아니라 자바스크립트의 자료형을 사용해야 합니다. 보통 첫 글자가 소문자면 타입스크립트의 자료형이고, 첫 글자가 대문자면 자바스크립트의 자료형입니다. |
| @Exclude( { 옵션객체 } ) | 하나의 DTO를 request, response에서 사용할 때 요청 객체와 응답 객체에 필요한 데이터가 다를 때 데이터를 제외하기 위해 사용합니다. 프로퍼티 대신 클래스에 선언할 수 있습니다. 두 가지 옵션이 있습니다. toPlainOnly: 클래스를 객체로 변환 시. reponse에 사용 toClassOnly: 객체를 클래스로 변환 시. request에 사용 |
| @Expose( {옵션객체} ) | 프로퍼티의 getter를 만들어줍니다. 프로퍼티에도 사용할 수 있습니다. (클래스를 @Exclude()로 변경 후 필요한 것만 포함) 옵션객체에 name: string을 전달해 프로퍼티명이 아니라 다른 이름으로 객체를 전달 할 수 있습니다. |
모델을 이용한 데이터 직렬화
모델을 이용해 데이터 직렬화를 하려면 두 단계를 거쳐야 합니다.
- 모델 파일 수정
- 컨트롤러에 인터셉터 추가
모델 파일 수정
import { Exclude, Expose, Transform } from 'class-transformer';
export class UserEntity {
id: number;
firstName: string;
lastName: string;
@Exclude() // 속성 제외
password: string;
@Expose() // 속성 추가
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
// 데이터 변환
@Transform(({ value }) => value.name)
role: RoleEntity;
}
컨트롤러에 인터셉터 추가
@UseInterceptors(ClassSerializerInterceptor)
@Get()
findOne(id): UserEntity {
return await this.userService.findOne(id);
}
DTO를 이용한 직렬화
DTO를 이용해 데이터 직렬화를 하려면 세 단계를 거쳐야 합니다.
- DTO 수정
- 사용자 정의 인터셉터 작성
- 컨트롤러에 인터셉터 추가
DTO 수정
import { Expose } from 'class-transformer';
export class UserDto {
@Expose()
id: number;
@Expose()
email: string;
}
사용자 정의 인터셉터 작성
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
import { plainToClass } from 'class-transformer';
import { map, Observable } from 'rxjs';
export class SerializeInterceptor implements NestInterceptor {
constructor(private dto: any) {}
intercept(
context: ExecutionContext,
next: CallHandler<any>,
): Observable<any> | Promise<Observable<any>> {
return next.handle().pipe(
map((data: any) => {
// 2번 매개변수를 1번 매개변수로 전달된 형식으로 변환
return plainToClass(this.dto, data, {
excludeExtraneousValues: true, // @Expose() 데코레이터가 정의된 프로퍼티만 반환
});
}),
);
}
}
컨트롤러에 인터셉터 추가
@UseInterceptors(new SerializeInterceptor(UserDto))
@Get()
findOne(id): UserDto {
return await this.userService.findOne(id);
}
데코레이터를 사용한 인터셉터 적용
인터셉터 적용 코드가 너무 길다면 데코레이터를 사용해 코드 작성을 줄일 수 있습니다.
아래처럼 인터페이스를 만들고 함수를 작성하면 @UseInterceptors() 데코레이터 대신 @Serialize() 데코레이터를 사용할 수 있습니다.
// 매개변수에 클래스만 입력 받기 위해 만드는 인터페이스
interface ClassConstructor {
new (...args: any[]): {}
}
export function Serialize(dto: ClassConstructor) {
return UseInterceptors(new SerializeInterceptor(dto));
}
'NestJS > NestJS 자체 문서화' 카테고리의 다른 글
| 미들웨어(Middleware) (0) | 2025.12.31 |
|---|---|
| 가드(Guard) (0) | 2025.12.31 |
| 예외 필터 (0) | 2025.12.31 |
| 파이프(Pipe), DTO (0) | 2025.12.31 |
| 프로바이더, 서비스 (0) | 2025.12.31 |