REST API - DTO czy nie? [Zamknięte]

154

Obecnie tworzę REST-API dla projektu i czytam artykuł o artykule o najlepszych praktykach. Wiele z nich wydaje się być przeciwnych DTO i po prostu ujawnia model domeny, podczas gdy inni wydają się uważać, że DTO (lub modele użytkowników, czy jakkolwiek chcesz to nazwać) są złą praktyką. Osobiście uważałem, że ten artykuł ma dużo sensu.

Rozumiem jednak również wady DTO z całym dodatkowym kodem mapującym, modelami domen, które mogą być w 100% identyczne z ich odpowiednikami w DTO i tak dalej.

Nasze API jest tworzone głównie po to, aby inni klienci mogli korzystać z danych, jednak jeśli zrobimy to dobrze, chcielibyśmy również użyć go do naszego własnego internetowego interfejsu GUI, jeśli to możliwe.

Chodzi o to, że możemy nie chcieć ujawniać wszystkich danych domeny innym użytkownikom klienta. Wiele danych ma sens tylko w naszej aplikacji internetowej. Ponadto możemy nie chcieć ujawniać wszystkich danych o obiekcie we wszystkich scenariuszach, zwłaszcza relacji z innymi obiektami i tak dalej. Na przykład, jeśli ujawnimy listę określonego obiektu, niekoniecznie będziemy chcieli ujawnić całą hierarchię obiektów; aby dzieci obiektu nie były ujawniane, ale można je było wykryć poprzez linki (hateoas).

Jak mam rozwiązać ten problem? Zastanawiałem się nad użyciem miksów Jacksona w naszych modelach domeny, aby kontrolować, jakie dane zostaną ujawnione w różnych scenariuszach. A może powinniśmy po prostu używać DTO do końca - nawet biorąc pod uwagę jego wady i kontrowersje?

benbjo
źródło
9
Nie zdziw się, jeśli to pytanie zostanie zamknięte. Jest to bardziej pytanie oparte na dyskusji, co oznacza, że ​​nie ma jasnej, poprawnej odpowiedzi. Zapytaj różne osoby, a otrzymasz inną odpowiedź.
Ben Thurley,
2
Link do artykułu ( ibm.com/developerworks/community/blogs/barcia/entry/… ) jest uszkodzony.
pinkpanther
7
@pinkpanther To świetny artykuł i szkoda, że ​​nie jest już dostępny. Oto wersja buforowana archiwum sieci Web .
kasiomolina

Odpowiedzi:

251

Dlaczego powinieneś używać DTO w swoim REST API

DTO oznacza D ata T ransfer O bject .

Wzorzec ten został stworzony w bardzo dobrze określonym celu: przesyłanie danych do zdalnych interfejsów , podobnie jak usługi sieciowe . Ten wzorzec bardzo dobrze pasuje do REST API, a DTO zapewni Ci większą elastyczność w dłuższej perspektywie.

Modele, które reprezentują domenę Twojej aplikacji i modele, które reprezentują dane obsługiwane przez Twój interfejs API są (lub przynajmniej powinny być) różnymi problemami i powinny być od siebie oddzielone . Nie chcesz przerywać klientów interfejsu API podczas dodawania, usuwania lub zmiany nazwy pola z modelu domeny aplikacji.

Podczas gdy warstwa usług działa w modelach domeny / trwałości, kontrolery interfejsu API powinny działać na innym zestawie modeli. W miarę ewolucji modeli domeny / trwałości w celu obsługi nowych wymagań biznesowych, na przykład możesz chcieć utworzyć nowe wersje modeli interfejsu API, aby obsługiwać te zmiany. Możesz również chcieć wycofać stare wersje swojego interfejsu API w miarę wydawania nowych wersji. I jest to całkowicie możliwe, gdy rzeczy są odsprzężone.


Wystarczy wspomnieć o kilku zaletach ujawniania DTO zamiast modeli trwałości:

  • Oddziel modele trwałości od modeli API.

  • DTO mogą być dostosowane do twoich potrzeb i są świetne, gdy ujawniają tylko zestaw atrybutów twoich encji trwałości. Nie będziesz potrzebować adnotacji, takich jak @XmlTransienti, @JsonIgnoreaby uniknąć serializacji niektórych atrybutów.

  • Korzystając z DTO, unikniesz piekła adnotacji w swoich encjach trwałości, to znaczy, że twoje encje trwałości nie będą nadęte adnotacjami niezwiązanymi z trwałością.

  • Będziesz mieć pełną kontrolę nad atrybutami, które otrzymujesz podczas tworzenia lub aktualizowania zasobu.

  • Jeśli używasz Swaggera , możesz używać adnotacji @ApiModeli @ApiModelPropertydo dokumentowania modeli interfejsu API bez naruszania jednostek trwałości.

  • Możesz mieć różne DTO dla każdej wersji twojego API.

  • Będziesz mieć większą elastyczność podczas mapowania relacji.

  • Możesz mieć różne DTO dla różnych typów mediów.

  • Twoje DTO mogą mieć listę linków do HATEOAS . Tego rodzaju rzeczy nie powinny być dodawane do obiektów trwałości. Korzystając z Spring HATEOAS , możesz rozszerzyć swoje klasy DTO RepresentationModel(wcześniej znane jako ResourceSupport) lub opakować je EntityModel(wcześniej znane jako Resource<T>).

Radzenie sobie z kodem standardowym

Nie będziesz musiał ręcznie mapować swoich encji trwałości na DTO i odwrotnie . Istnieje wiele struktur mapowania, których możesz użyć, aby to zrobić. Na przykład spójrz na MapStruct , który jest oparty na adnotacjach i działa jako procesor adnotacji Maven. Działa dobrze zarówno w aplikacjach opartych na CDI, jak i Spring.

Można również rozważyć Lombok do generowania pobierające, ustawiaczy, equals(), hashcode()i toString()metod dla Ciebie.


Powiązane: Aby nadać lepsze nazwy klasom DTO, zapoznaj się z tą odpowiedzią .

kasiomolina
źródło
2
Gdybym poszedł drogą DTO, czy zamapowałbyś wszystkie obiekty domeny na DTO, czy tylko te, które nie byłyby identyczne? Ponadto, jak rozwiązałbyś problem ujawniania danych w oparciu o różne scenariusze / konteksty? Wiele DTO na obiekt domeny?
benbjo
6
@benbjo To zależy od Ciebie. Zwykle mapuję tylko najbardziej złożone jednostki na DTO, encje, dla których nie chcę, aby wszystkie atrybuty były ujawniane, i jednostki z wieloma relacjami. DTO daje mi elastyczność posiadania listy linków do wykorzystania w HATEOAS. Tego rodzaju rzeczy nie dodałbym do moich obiektów trwałości.
kasiomolina
2
@molin bardzo dziękuję za informacje i sugestie. Na pewno sprawdzę MapStruct. Na pierwszy rzut oka wygląda na to, że bardzo dobrze odpowiada moim potrzebom.
benbjo
6
Drogi przeciwniku, czy mógłbyś przynajmniej wyjaśnić powód swojego głosu przeciw?
kasiomolina
8
Istnieje również architektoniczny powód, aby używać DTO zamiast jednostek domeny w REST API. REST API nie powinno się zmieniać, aby uniknąć uszkodzenia istniejących klientów. Jeśli używasz modelu domeny bezpośrednio w interfejsie API, tworzysz niepożądane sprzężenie między interfejsem API a modelem domeny. Zgodnie z zasadą projektową Service Loose Coupling, umowa serwisowa nie powinna być ściśle powiązana z logiką usługi lub szczegółami implementacji.
Paulo Merson
25

Kiedy twoje API jest publiczne i musisz obsługiwać wiele wersji, musisz iść z DTO.

Z drugiej strony, jeśli jest to prywatne API i kontrolujesz zarówno klienta, jak i serwer, zwykle pomijam DTO i ujawniam bezpośrednio model domeny.

David Siro
źródło
Zgadzam się z tobą w ostatniej części i zwykle to robię, ale to jest moje pierwsze publiczne API. Rozważę, co powiesz o używaniu DTO w części publicznej. Być może prywatna i publiczna część interfejsu API rzeczywiście powinna być oddzielna, nawet jeśli „zjedz własną wersję testową” jest dobrą zasadą.
benbjo
11

Zwykle używam DTO.

Nie podobają mi się wady, ale wydaje mi się, że inne opcje są jeszcze gorsze:

Ekspozycja obiektów domeny może prowadzić do problemów z bezpieczeństwem i wycieku danych. Może się wydawać, że adnotacje Jacksona rozwiązują problem, ale zbyt łatwo jest popełnić błąd i ujawnić dane, których nie należy ujawniać. Projektując klasę DTO o wiele trudniej popełnić taki błąd.

Z drugiej strony wady podejścia DTO można zredukować dzięki takim rzeczom, jak mapowanie obiektu na obiekt i Lombok dla mniejszego schematu.

Argb32
źródło
9

Jak już powiedziałeś, jest to wyraźnie pytanie związane z opinią. Sama bardziej pociąga mnie podejście bez DTO, po prostu ze względu na cały potrzebny standardowy kod.

Dotyczy to głównie strony odpowiedzi interfejsu API json / rest. Napisałem nawet dodatek do Jacksona, aby uniknąć pisania wielu widoków / filtrów json dla tych przypadków: https://github.com/Antibrumm/jackson-antpathfilter

Z drugiej strony DTO są dobrą rzeczą po stronie żądań takich interfejsów API. Praca bezpośrednio na obiektach może być dość trudna, biorąc pod uwagę na przykład relacje dwukierunkowe. Nie chcesz też pozwalać dzwoniącemu na modyfikowanie na przykład atrybutu „twórca”. Dlatego podczas mapowania takich żądań należałoby odrzucić pewne pola.

Martin Frey
źródło
2
Zgadzam się, że moje pytanie jest w pewnym stopniu związane z opinią (i odradzane), ale szukałem też wskazówek, jak rozwiązać mój problem. Dużo wezmę na twój dodatek Jacksona, ale czy uważasz, że używanie mixinów do kontrolowania, jakie dane powinny być ujawniane w różnych scenariuszach, jest dobrym pomysłem?
benbjo