과정을 즐기자

요청과 응답에서 엔티티를 직접 사용하면 안되는 이유 본문

Spring

요청과 응답에서 엔티티를 직접 사용하면 안되는 이유

320Hwany 2023. 2. 23. 16:45

이번 글에서는 요청과 응답에서 엔티티를 직접 사용하면 안되는 이유에 대해서 작성해보려고 합니다.

일단.. 너무 기계적으로 dto를 사용했기 때문에 왜 dto가 필요한지를 생각해보려고 합니다.

 

@Override
public void save(Member member) {
    memberJpaRepository.save(member);
}

 

먼저 스프링 데이터 JPA를 사용한 Member의 회원 가입을 예시로 들어서 설명하겠습니다.

위와 같이 Member 엔티티를 저장할 수 있습니다. repository에서 save를 할 때는 엔티티를 직접 사용하지만

회원 가입을 위해 회원이 입력한 데이터를 controller에서 받고.. service 계층을 거쳐 repository까지 엔티티를

전달하는 방식은 바람직한 방식은 아닙니다.

서비스가 커지면 커질수록 기능이 많아지며 회원가입, 회원수정, 회원삭제와 같은 단순한 CRUD 기능만 있는 것이

아닙니다. 이때 각각에 맞는 Dto를 생성해서 요청하고 응답하는 것이 좋은 방법입니다.

 

이유는 크게 3가지가 있습니다.

 

1. 외부에 엔티티 스펙을 노출할 수 있다.

2. 엔티티 스펙이 변한다면 모든 것을 바꿔야한다.  

3. 순환참조 문제가 발생한다.

 

엔티티를 직접 사용할 때의 문제점

1. 외부에 엔티티 스펙을 노출할 수 있다.

엔티티로 직접 요청하고 반환한다면 외부에서 쉽게 서비스의 엔티티를 확인할 수 있기 때문에

보안상으로 문제가 될 수 있습니다.

 

2. 엔티티 스펙이 변한다면 모든 것을 바꿔야 한다.

회원가입, 회원 수정, 회원 조회, ..  모든 기능에 같은 엔티티를 사용한다면 엔티티 스펙이 바뀌었을 때

모든 기능에서 변경을 해줘야합니다. 하지만 Dto를 사용한다면 엔티티 스펙이 변경되더라도 

필요한 부분의 기능만 선택해서 수정할 수 있고 각각 필요한 @Valid를 사용할 수도 있습니다.

 

3. 순환참조 문제가 발생한다.

 

Author

@Getter
@NoArgsConstructor(access = PROTECTED)
@Entity
public class Author extends BaseTimeEntity {

	...

    @OneToMany(mappedBy = "author", cascade = CascadeType.REMOVE)
    private List<Cartoon> cartoonList = new ArrayList<>();
    
    ...
    
}

 

Cartoon

@Getter
@NoArgsConstructor(access = PROTECTED)
@Entity
public class Cartoon extends BaseTimeEntity {

	... 
    
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "author_id")
    private Author author;
    
    ...
    
}

엔티티 Cartoon, Author가 있고 다대일 양방향 매핑이라고 해보겠습니다.

이때 만약 Cartoon 엔티티를 직접 반환한다면 이 안에 있는 Author 엔티티도 반환되며

Author안에는 다시 Cartoon이 있기 때문에 순환참조가 발생하게됩니다.  

물론 라이브러리 설정, @JsonIgnore 등을 사용하여 엔티티를 직접 반환할 수도 있지만

별로 바람직한 방법은 아니라고 생각하기 때문에 Dto를 사용해야 한다고 생각합니다.