programing

Spring Data REST가 DTO를 사용하지 않고 REST 리소스를 통해 엔티티를 노출하는 것이 문제가 있습니까?

megabox 2023. 8. 12. 10:10
반응형

Spring Data REST가 DTO를 사용하지 않고 REST 리소스를 통해 엔티티를 노출하는 것이 문제가 있습니까?

저의 제한된 경험으로, 저는 당신이 엔티티를 프론트 엔드나 휴식을 통해 전달하지 말고 DTO를 사용해야 한다고 반복적으로 들었습니다.

Spring Data Rest는 정확히 이렇게 하지 않습니까?저는 간략하게 예측을 살펴보았지만, 이러한 예측은 반환되는 데이터를 제한하는 것처럼 보이며, 여전히 데이터베이스에 저장할 포스트 메서드에 대한 매개 변수로 엔터티를 기대합니다.제가 여기서 뭔가를 놓치고 있는 것일까요, 아니면 제가 (그리고 제 동료들이) 절대 주변을 지나쳐서는 안 된다는 점에서 잘못된 것일까요?

tl;dr

아니요. DTO는 HTTP 리소스에 노출된 표현과 서버 측 도메인 모델을 분리하는 하나의 수단일 뿐입니다.스프링 데이터 REST가 수행하는 다른 디커플링 방법도 사용할 수 있습니다.

세부 사항

예, Spring Data REST는 서버 측에 있는 도메인 모델을 검사하여 노출되는 리소스의 표현 방식에 대해 추론합니다.그러나 도메인 개체의 순진한 노출이 가져올 문제를 완화하는 몇 가지 중요한 개념을 적용합니다.

Spring Data REST는 집계를 찾고 기본적으로 그에 따라 표현을 형상화합니다.

순진한 "나는 잭슨 앞에 내 도메인 객체를 던진다"는 기본적인 문제는 일반 엔티티 모델에서 합리적인 표현 경계에 대해 추론하기가 매우 어렵다는 것입니다.특히 데이터베이스 테이블에서 파생된 엔티티 모델은 사실상 모든 것을 모든 것에 연결하는 습관이 있습니다.이는 Aggregate와 같은 중요한 도메인 개념이 대부분의 지속성 기술(특히 관계형 데이터베이스)에 존재하지 않기 때문입니다.

하지만 이 경우 "도메인 모델을 노출하지 않음"은 문제의 핵심보다는 증상에 더 영향을 준다고 생각합니다.도메인 모델을 올바르게 설계하면 도메인 모델의 이점과 상태 변화를 통해 해당 모델을 효과적으로 추진할 수 있는 우수한 표현 사이에 큰 중복이 발생합니다.몇 가지 간단한 규칙:

  • 다른 개체와의 모든 관계에 대해 자문해 보십시오. 이것이 오히려 도움이 되는 참조가 될 수 있지 않을까요?객체 참조를 사용하면 관계의 다른 측면에 있는 많은 의미론을 엔티티로 끌어옵니다.이를 잘못 이해하면 일반적으로 엔티티를 참조하는 엔티티로 이어지는데, 이는 더 깊은 차원의 문제입니다.표현 수준에서는 데이터를 차단하고 일관성 범위를 조정할 수 있습니다.
  • 양방향 관계는 업데이트 측면에서 제대로 파악하기 어렵기로 악명 높기 때문에 방지하십시오.

Spring Data REST는 이러한 엔티티 관계를 HTTP 수준의 적절한 메커니즘으로 실제로 전송하기 위해 여러 가지 작업을 수행합니다. 일반적으로 링크, 그리고 더 중요한 것은 이러한 관계를 관리하는 전용 리소스에 대한 링크입니다.엔티티에 대해 선언된 리포지토리를 검사하여 이를 수행하며 기본적으로 관련 엔티티에 대한 필수 인라인을 해당 관계를 명시적으로 관리할 수 있는 연결 리소스에 대한 링크로 대체합니다.

이러한 접근 방식은 일반적으로 HTTP 수준에서 DDD 집계에 의해 설명되는 일관성 보장과 잘 작동합니다.PUT요청은 기본적으로 여러 Aggregate에 걸쳐 있지 않습니다. 이는 도메인의 개념과 일치하는 리소스의 일관성 범위를 의미하기 때문에 좋은 결과입니다.

DTO가 도메인 개체의 필드만 복제하는 경우 사용자를 DTO로 강제하는 것은 의미가 없습니다.

도메인 개체에 대해 원하는 만큼 DTO를 도입할 수 있습니다.대부분의 경우 도메인 개체에 캡처된 필드는 어떤 방식으로든 표현에 반영됩니다.나는 아직 실체를 보지 못했습니다.Customer함을 firstname,lastname그리고.emailAddress재산, 그리고 표현에 전혀 관련이 없는 것들.

DTO의 도입은 결코 디커플링을 보장하지 않습니다.저는 화물 재배를 이유로 도입된 프로젝트들을 너무 많이 보았습니다. 단순히 지원하는 엔티티의 모든 분야를 복제했고 모든 새로운 분야도 DTO에 추가해야 했기 때문에 추가적인 노력을 야기했습니다.하지만, 디커플링!아닙니다. ¯\_(ツ)_/¯

그렇긴 하지만, 특히 강력하게 입력된 값 객체를 사용하는 경우에는 이러한 속성의 표현을 약간 조정하고 싶은 상황이 있습니다.EmailAddress(좋습니다!) 하지만 여전히 이것을 평원으로 표현하고 싶습니다.StringJSON이.하지만 문제는 결코 아닙니다.Spring Data REST는 주석, 도메인 유형 외부에 주석을 보관하기 위한 믹스인, 사용자 지정 일련 번호 등 표현을 조정할 수 있는 다양한 방법을 제공하는 표지 아래에서 Jackson을 사용합니다.그래서 그 사이에 지도층이 있습니다.

기본적으로 DTO를 사용하지 않는 것 자체가 나쁜 것은 아닙니다.모든 것에 대해 DTO를 작성해야 하는 경우 필요한 보일러 플레이트의 양에 대한 사용자들의 항의를 상상해 보십시오!DTO는 목적을 위한 하나의 수단일 입니다.만약 그 목적이 다른 방법으로 달성될 수 있다면(그리고 보통 가능하다면) 왜 DTO를 고집해야 합니까?

요구 사항에 맞지 않는 Spring Data REST는 사용하지 마십시오.

커스터마이징 작업을 계속하면서 Spring Data REST는 API가 구현하는 기본 REST API 구현 패턴을 따르는 부분을 정확하게 다루기 위해 존재한다는 점에 주목할 필요가 있습니다.그리고 그 기능은 당신에게 더 많은 생각할 시간을 주기 위해 준비되어 있습니다.

  1. 도메인 모델을 구성하는 방법
  2. API의 어떤 부분이 하이퍼미디어 기반 상호 작용을 통해 더 잘 표현되는지 확인할 수 있습니다.

다음은 SpringOne Platform 2016에서 진행한 강연의 슬라이드로 상황을 요약한 것입니다.

What makes up a REST API built with Spring Data REST

전체 슬라이드 데크는 여기에서 찾을 수 있습니다.InfoQ에서 제공되는 강연 녹음도 있습니다.

Spring Data REST는 밑줄 친 원에 초점을 맞출 수 있도록 합니다.Spring Data REST를 켜는 것만으로 정말 훌륭한 API를 구축할 수 있다고는 생각하지 않습니다.우리는 단지 당신이 흥미로운 부분들에 대해 더 많은 시간을 가질 수 있도록 보일러 플레이트의 양을 줄이고 싶습니다.

일반적으로 Spring Data와 마찬가지로 표준 지속성 작업을 위해 작성되는 상용판 코드의 양이 줄어듭니다.아무도 CRUD 작업만으로 실제 앱을 구축할 수 있다고 주장하지 않을 것입니다.하지만 지루한 부분에서 노력을 빼면서, 우리는 당신이 실제 도메인 문제에 대해 더 집중적으로 생각할 수 있게 해줍니다 (그리고 당신은 실제로 그렇게 해야 합니다 :).

원하는 경우 도메인 유형을 DTO에 수동으로 매핑하는 등 특정 리소스를 재정의하여 해당 리소스의 동작을 완전히 제어할 수 있습니다.또한 Spring Data REST가 제공하는 기능 옆에 맞춤형 기능을 배치하고 두 기능을 연결하기만 하면 됩니다.당신이 사용하는 것에 대해 선택하세요.

샘플

RESTful Web Services 책에 있는 RESTBucks 예제의 Spring(데이터 REST) 기반 구현인 Spring RESTBucks에서 설명한 내용의 약간 고급 예제를 찾을 수 있습니다.Spring Data REST를 사용하여 관리Order사용자 지정 요구 사항을 도입하고 스토리의 지불 부분을 수동으로 완전히 구현하기 위해 인스턴스를 조정하지만 처리를 조정합니다.

Spring Data REST를 사용하면 데이터베이스 구조를 기반으로 REST API를 매우 빠르게 프로토타입화하고 만들 수 있습니다.우리는 다른 프로그래밍 기술과 비교할 때 몇 분 대 며칠에 대해 이야기하고 있습니다.

REST API가 데이터베이스 구조와 밀접하게 연결되어 있다는 것이 그 대가입니다.때때로, 그것은 큰 문제입니다.가끔은 그렇지 않습니다.기본적으로 데이터베이스 설계의 품질과 API 사용자의 요구에 맞게 설계를 변경할 수 있는지 여부에 따라 달라집니다.

요약하자면, Spring Data REST는 특정 특수 상황에서 많은 시간을 절약할 수 있는 도구라고 생각합니다.어떤 문제에도 적용될 수 있는 은총이 아닙니다.

이전에는 프로젝트의 모든 엔티티에 대해 완전한 기존 계층화(데이터베이스, DTO, 저장소, 서비스, 컨트롤러 등)를 포함한 DTO를 사용했습니다.DTO들을 호핑하는 것은 언젠가 우리의 생명을 구할 것입니다 :)

그서간단게하래▁a▁so게.City이 있는 .id,name,country,state우리는 아래와 같이 했습니다.

  1. City와의식으로 된 id,name,county,....
  2. CityDTO와 함께id,name,county,....속성(데이터베이스와 정확히 동일)
  3. CityRepositoryfindCity(id),....
  4. CityService와 함께findCity(id) { CityRepository.findCity(id) }
  5. CityController와 함께findCity(id) { ConvertToJson( CityService.findCity(id)) }

고객에게 도시 정보를 노출하기에는 상용구 코드가 너무 많습니다.이것은 단순한 개체이기 때문에 이러한 계층을 따라 어떠한 비즈니스도 수행되지 않고 단지 객체만 지나갑니다.City계층을 (예: " " " 를 하는 것")location음, 에 산, 음, 왜면마막지는에하냐재▁at,▁property는마지에막▁because면▁well▁the하▁the▁end.location속성은 다음과 같이 사용자에게 노출되어야 합니다.json . . . . . findByNameAndCountryAllIgnoringCase메소드는 모든 레이어를 변경해야 합니다(각 레이어에 새 메소드가 필요함).

Rest(스프링 데이터 정지)를of course with Spring Data이 아닙니다 이것은 단순한 것이 아닙니다!

public interface CityRepository extends CRUDRepository<City, Long> {
   City findByNameAndCountryAllIgnoringCase(String name, String country);
}

city엔티티는 최소 코드로 클라이언트에 노출되지만 여전히 도시가 노출되는 방식을 제어할 수 있습니다.Validation,Security,Object Mapping다 거기에 있습니다.모든 것을 조정할 수 있습니다.

를 들어, 알 수 없도록 다음과 같이 .city엔티티 속성 이름 변경(계층 분리), https://docs.spring.io/spring-data/rest/docs/3.0.2.RELEASE/reference/html/ #customizing-sdr.customizing-deserialization에 언급된 사용자 지정 개체 매퍼를 사용할 수 있습니다.

요약하자면

많이 하며, 계층화를 할 수 Spring Data Rest, Spring Data Rest, Spring Data Rest를 할 수 .Service그리고.Controller볼일을 보다

클라이언트/서버 릴리스에서 두 개 이상의 아티팩트를 게시합니다.이것은 이미 클라이언트와 서버를 분리합니다.서버의 API가 변경되어도 애플리케이션은 즉시 변경되지 않습니다.애플리케이션이 JSON을 직접 사용하는 경우에도 레거시 API를 계속 사용합니다.

그래서, 디커플링은 이미 존재합니다.중요한 것은 서버의 API가 출시된 후에 진화할 가능성이 있는 다양한 방법에 대해 생각하는 것입니다.

저는 주로 DTO를 사용하는 프로젝트와 서버의 SQL과 사용 중인 애플리케이션 사이의 수많은 견고한 보일러 플레이트 층을 사용하는 프로젝트를 담당합니다.강성 커플링은 이러한 응용 분야에서도 가능합니다.종종 DB 스키마의 내용을 변경하려면 새로운 엔드포인트 집합을 구현해야 합니다.그런 다음 각 계층에서 함께 제공되는 보일러 플레이트(클라이언트, DTO, POJO, DTO <-> POJO 변환, 컨트롤러, 서비스, 저장소, DAO, JDBC <-> POJO 변환 및 SQL)와 함께 두 가지 엔드포인트 세트를 모두 지원합니다.

프레임워크에서 지원하지 않는 작업을 수행할 때 동적 코드(스프링 데이터-레스트 등)에 비용이 든다는 것은 인정합니다.예를 들어, 당사의 서버는 많은 배치 삽입/업데이트 작업을 지원해야 합니다.단일 사례에서 이러한 사용자 지정 동작만 필요한 경우 스프링 데이터를 사용하지 않고 구현하는 것이 확실히 더 쉽습니다.사실, 그것은 너무 쉬울 수도 있습니다.그 단일 사례들은 증가하는 경향이 있습니다.DTO와 함께 제공되는 코드의 수가 증가함에 따라 불일치는 결국 유지하기가 매우 부담스럽습니다.일부 비동적 서버 구현에서는 더 이상 어떤 서버에서도 사용되지 않을 수 있는 수백 개의 DTO 및 POJO가 있습니다.하지만, 우리는 그들의 수가 매달 증가함에 따라 그들을 계속 지원할 수 밖에 없습니다.

Spring-data-rest를 사용하면 커스터마이징 비용을 조기에 지불할 수 있습니다.다중 계층 하드 코드 구현을 사용하면 나중에 비용을 지불합니다.어떤 것이 선호되는지는 많은 요인(팀의 지식 및 프로젝트의 예상 수명 포함)에 따라 달라집니다.두 가지 유형의 프로젝트 모두 자체 무게로 인해 붕괴될 수 있습니다.하지만 시간이 지나면서 더 역동적인 구현(DTO가 없는 스프링 데이터 레스트 등)에 익숙해졌습니다.이는 프로젝트에 좋은 사양이 없을 때 특히 그렇습니다.시간이 지남에 따라 이러한 프로젝트는 보일러 플레이트의 바다에 묻혀 있는 불일치에 쉽게 익사할 수 있습니다.

스프링 문서에서 봄 데이터 REST는 엔티티를 노출하지 않습니다. 사용자가 이 작업을 수행합니다.Spring Data 프로젝트는 서로 다른 데이터 소스에 액세스하는 프로세스를 용이하게 하기 위한 것이지만, Spring Data Rest에서 노출할 계층은 사용자가 결정합니다.

프로젝트를 재구성하면 문제를 해결하는 데 도움이 됩니다.

Spring 데이터를 사용하여 생성하는 모든 @Repository는 Repository보다 설계 측면에서 DAO를 더 많이 나타냅니다.각 데이터 소스는 사용자가 액세스하려는 특정 데이터 소스와 긴밀하게 연결되어 있습니다.JPA, 몽고, 레디스, 카산드라...이러한 도면층은 도면요소 표현 또는 투영을 반환합니다.

그러나 설계 관점에서 리포지토리 패턴을 확인할 경우 애플리케이션이 해당 DAO를 사용하여 필요한 만큼의 다양한 소스로부터 정보를 얻고 애플리케이션에 대한 비즈니스 특정 개체를 구축하는 특정 DAO에서 더 높은 추상화 계층을 가져야 합니다(DTO와 더 유사할 수 있음).Spring Data Rest에 표시할 계층이 이에 해당합니다.

참고: 엔티티 인스턴스가 DTO와 동일한 속성을 가지고 있기 때문에 이 인스턴스만 반환하도록 권장하는 답변이 표시됩니다.이것은 일반적으로 좋지 않은 관행이며 특히 봄과 많은 다른 프레임워크에서는 좋지 않은 생각입니다. 왜냐하면 그들은 당신의 실제 클래스를 반환하지 않고 프록시 래퍼를 반환하여 그들이 값의 게으른 로딩 등과 같은 마법을 사용할 수 있기 때문입니다.

언급URL : https://stackoverflow.com/questions/38874746/is-it-problematic-that-spring-data-rest-exposes-entities-via-rest-resources-with

반응형