🚩 요청과 응답으로 엔티티를 직접 사용하지 말고 DTO
를 정의하여 요청과 응답의 객체로 사용하자 !
도메인의 핵심 로직과 속성을 가지고 실제 DB의 테이블과 매칭되는 클래스.
getter
, setter
를 쓰게 되면 비즈니스 로직과 크게 상관없는 곳에서 자원의 속성이 변경될 수 있다.
엔티티를 UI 계층에 노출하는 것은 테이블 설계를 화면에 공개하는 것이나 다름없으므로 보안상으로도 바람직하지 못하다.
애플리케이션이 확장되면 엔티티의 크기는 점차 커지게 되는데 따라서 API스펙도 더 많아질 것이다. 이 때 요청과 응답으로 엔티티를 사용하게 되면 요청하는 화면에 필요하지 않은 속성까지도 함께 보내지게 된다. 이렇게 되면 속도도 느려지게 되는데 @JsonIgnore
어노테이션을 사용하면 화면으로 속성이 보내지지 않지만 근본적인 해결책이 되지 못한다.
엔티티를 보내면 어떤 속성이 화면으로 보내지는 지 혹은 무시되는 지 한 눈에 알아보기 어렵다.
엔티티를 보내면 user가 사용되는 다양한 API에 따른 필요한 속성들을 동적으로 선택할 수 없다.
DTO를 보내면 화면에서 요구하는 필요한 데이터들만 선별하여 요청과 응답을 할 수 있다.
양방향 참조를 사용했다면 순환참조를 조심해야 하는데, 양방향 참조된 엔티티를 컨트롤러에서 응답으로 리턴하면 엔티티가 참조하고 있는 객체는 지연 로딩되고, 로딩된 객체는 또 다시 본인이 참조하고 있는 객체를 호출하게 된다. 이렇게 서로 참조하는 객체를 계속 호출하면서 결국 무한 루프에 빠지게 되는 문제가 발생한다.
따라서 양방향 연관관계에서 둘 중에 하나를 @JsonIgnore
해줘야 하나 엔티티가 바뀌면 api스펙도 모두 바뀌어버린다.
@NotNull
, @NotEmpty
, @NotBlank
와 같은 요청에 대한 값의 validation코드가 들어가면 엔티티 클래스는 더 복잡해지고 가독성이 저하된다.📌 DTO를 모든 API마다 구별해서 만들다 보면 너무 많은 DTO가 생겨 관리하기 어려울 수 있다. 그러나 요청과 응답으로 엔티티를 사용하면 개발의 편리함을 얻을 순 있으나 애플리케이션의 결함을 얻게 될 수 있다.
📌 또한 API스펙과 엔티티 사이의 의존성이 생기는 문제도 생긴다.
UI와 도메인이 서로 의존성을 갖지 않고 독립적으로 개발하는 것을 지향해야하므로 이를 중간에서 연결시켜 주는 DTO의 역할은 매우 중요하다.
📌 요청과 응답으로 DTO를 사용하면 각각의 DTO 클래스가 데이터를 전송하는 클래스로서의 역할을 명확히 가질 수 있게 되고 이는 하나의 클래스가 하나의 역할을 해야한다는 객체지향의 정신과도 부합한다.