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?
Odpowiedzi:
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
@XmlTransient
i,@JsonIgnore
aby 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
@ApiModel
i@ApiModelProperty
do 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 jakoResourceSupport
) lub opakować jeEntityModel
(wcześniej znane jakoResource<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()
itoString()
metod dla Ciebie.Powiązane: Aby nadać lepsze nazwy klasom DTO, zapoznaj się z tą odpowiedzią .
źródło
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.
źródło
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.
źródło
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.
źródło