Entity -> DTO 변환. 서비스에서? 컨트롤러에서?
서비스에서 Entity -> DTO 변환
저는 아래와 같이 엔티티를 DTO로 변환하는 코드를 서비스에 작성했습니다. 하지만 그렇게 작성하니 문제가 발생했습니다.
<auth.controller.ts>
async signup(@Body() signupDto: UserSignupDto): Promise<UserDto> {
return this.authService.signup(signupDto);
}
<auth.service.ts>
async signin(dto: UserSigninDto): Promise<boolean> {
const user = await this.userService.findUserEntityByEmail(dto.email);
if (!user) {
throw new UserIncorrectEmailException();
}
if (!(await compare(dto.password, user.password))) {
throw new UserIncorrectPasswordException();
}
return true;
}
<user.service.ts>
async findUserByEmail(email: string): Promise<UserDto | undefined> {
const user = await this.userRepository.findOneBy({ email });
if (!user) {
return undefined;
}
return UserDto.of(
user.id,
user.email,
user.address,
user.nickname
);
}
async findUserEntityByEmail(email: string): Promise<User | undefined> {
return await this.userRepository.findOneBy({ email });
}
auth.service의 signin() 메서드에서 user.service의 메서드를 통해 유저를 가져와 클라이언트가 보낸 비밀번호와 대조하고 있습니다. user.service의 findByEmail()는 userDto를 반환하므로 signin() 메서드 본문에서는 DB에 저장된 사용자의 비밀번호를 알 수 없습니다. 따라서 user.service에 findUserEntityByEmail() 메서드를 작성해야 하는데, 이렇게 작성하면 사실상 똑같은 일을 하는 메서드를 두 개 만든 것입니다. 이것은 signin() 메서드 같은 것들이 작성될 때마다 해당 메서드를 위해 중복 메서드를 작성해야 함을 의미합니다.
Controller에서 Entity -> Dto 변환
<auth.controller.ts>
async signup(@Body() signupDto: UserSignupDto): Promise<UserDto> {
const user = await this.authService.signup(signupDto);
return UserDto.of(
user.id,
user.email,
user.address,
user.nickname
);
}
<auth.service.ts>
async signin(dto: UserSigninDto): Promise<boolean> {
const user = await this.userService.findUserByEmail(dto.email);
if (!user) {
throw new UserIncorrectEmailException();
}
if (!(await compare(dto.password, user.password))) {
throw new UserIncorrectPasswordException();
}
return true;
}
<user.service.ts>
async findUserByEmail(email: string): Promise<User | undefined> {
return await this.userRepository.findOneBy({ email });
}
user.service에서 userDto를 반환하지 않고 user 객체를 그대로 반환했습니다. 이렇게 작성하면 signin() 메서드를 위한 중복 함수를 user.service에 작성하지 않아도 되고, 엔티티를 그대로 반환하므로 한 서비스에서 다른 서비스의 메서드를 사용할 때 반환값(dto)에 내가 원하는 값이 들어있는지 없는지 확인하지 않아도 됩니다. 위 같이 작성하면 컨트롤러 코드가 약간 복잡해지지만, 감당 못할 수준까지는 아니고, 무엇보다 user.service에 중복 메서드를 작성하지 않는다는 점이 서비스에서 엔티티를 DTO로 변환하는 방식보다 훨씬 좋아 보입니다.
한 발 더 물러나서, 인터셉터에서 Entity -> Dto 변환할까 생각해 보았는데, 하나의 Entity에 하나의 Dto만 존재하는 것이 아니므로 컨트롤러에서 인터셉터에게 어떤 DTO로 변환해야 한다는 정보를 전달해야 할 것 같은데, 그런 식으로 컨트롤러에서 인터셉터에게 메타데이터를 보낼 바에는 그냥 Controller에서 해당 변환을 책임지는 것이 더 좋아 보여서 최종적으로 컨트롤러에서 엔티티를 DTO로 변환하는 작업을 작성했습니다.
'NestJs' 카테고리의 다른 글
service에서의 repository 의존 역전하기 - 클린 아키텍처 적용하기 (0) | 2023.03.28 |
---|---|
NestJS - @Module(), @Injectable(), @InjectRepository() (0) | 2023.03.17 |
NestJS - passport (0) | 2023.03.13 |
NestJs - Guard (0) | 2023.03.09 |
NestJS 소개 (0) | 2022.10.23 |