Ich erstelle derzeit eine REST-API für ein Projekt und habe Artikel für Artikel über Best Practices gelesen. Viele scheinen gegen DTOs zu sein und legen einfach nur das Domänenmodell offen, während andere DTOs (oder Benutzermodelle oder wie auch immer Sie es nennen möchten) für eine schlechte Praxis halten. Persönlich dachte ich, dass dieser Artikel sehr viel Sinn macht.
Ich verstehe jedoch auch die Nachteile von DTOs mit all dem zusätzlichen Mapping-Code, Domänenmodellen, die möglicherweise zu 100% mit ihrem DTO-Gegenstück identisch sind, und so weiter.
Unsere API wurde größtenteils so erstellt, dass andere Clients Daten verwenden können. Wenn wir es jedoch richtig machen, möchten wir sie nach Möglichkeit auch für unsere eigene Web-GUI verwenden.
Die Sache ist, dass wir möglicherweise nicht alle Domänendaten für die anderen Clientbenutzer verfügbar machen möchten. Ein Großteil der Daten ist nur in unserer eigenen Webanwendung sinnvoll. Außerdem möchten wir möglicherweise nicht in allen Szenarien alle Daten zu einem Objekt verfügbar machen, insbesondere nicht zu Beziehungen zu anderen Objekten usw. Wenn wir beispielsweise eine Liste eines bestimmten Objekts verfügbar machen, möchten wir nicht unbedingt die gesamte Objekthierarchie verfügbar machen. damit die Kinder des Objekts nicht entlarvt werden, sondern über Links (Hateoas) entdeckt werden können.
Wie soll ich dieses Problem lösen? Ich habe darüber nachgedacht, Jackson-Mixins in unseren Domain-Modellen zu verwenden, um zu steuern, welche Daten in verschiedenen Szenarien verfügbar gemacht werden. Oder sollten wir nur DTOs verwenden - trotz ihrer Nachteile und Kontroversen?
Antworten:
Warum Sie DTOs in Ihrer REST-API verwenden sollten
DTO steht für D ata T ransfer O bject .
Dieses Muster wurde mit einem sehr genau definierten Zweck erstellt: Übertragen von Daten auf Remote-Schnittstellen , genau wie bei Webdiensten . Dieses Muster passt sehr gut in eine REST-API und DTOs bieten Ihnen auf lange Sicht mehr Flexibilität .
Die Modelle, die die Domäne Ihrer Anwendung darstellen, und die Modelle, die die von Ihrer API verarbeiteten Daten darstellen, sind (oder sollten es zumindest sein) unterschiedliche Anliegen und sollten voneinander entkoppelt werden. Sie möchten Ihre API-Clients nicht beschädigen, wenn Sie ein Feld zum Anwendungsdomänenmodell hinzufügen, entfernen oder umbenennen.
Während Ihre Service-Schicht über die Domänen- / Persistenzmodelle arbeitet, sollten Ihre API-Controller über einen anderen Satz von Modellen arbeiten. Wenn sich Ihre Domänen- / Persistenzmodelle weiterentwickeln, um beispielsweise neue Geschäftsanforderungen zu unterstützen, möchten Sie möglicherweise neue Versionen der API-Modelle erstellen, um diese Änderungen zu unterstützen. Möglicherweise möchten Sie auch die alten Versionen Ihrer API verwerfen, wenn neue Versionen veröffentlicht werden. Und es ist durchaus möglich zu erreichen, wenn die Dinge entkoppelt sind.
Um nur einige Vorteile der Offenlegung von DTOs anstelle von Persistenzmodellen zu nennen:
Entkoppeln Sie Persistenzmodelle von API-Modellen.
DTOs können auf Ihre Anforderungen zugeschnitten werden und eignen sich hervorragend, wenn nur eine Reihe von Attributen Ihrer Persistenzentitäten verfügbar gemacht werden . Sie benötigen keine Anmerkungen wie
@XmlTransient
und@JsonIgnore
, um die Serialisierung einiger Attribute zu vermeiden.Durch die Verwendung von DTOs vermeiden Sie eine Menge Annotationen in Ihren Persistenzentitäten, dh Ihre Persistenzentitäten werden nicht mit nicht persistenzbezogenen Annotationen aufgebläht.
Sie haben die volle Kontrolle über die Attribute, die Sie beim Erstellen oder Aktualisieren einer Ressource erhalten.
Wenn Sie Swagger verwenden , können Sie Ihre API-Modelle mithilfe von
@ApiModel
und@ApiModelProperty
Anmerkungen dokumentieren, ohne Ihre Persistenzentitäten zu beeinträchtigen.Sie können für jede Version Ihrer API unterschiedliche DTOs verwenden.
Sie haben mehr Flexibilität beim Zuordnen von Beziehungen.
Sie können verschiedene DTOs für verschiedene Medientypen haben.
Ihre DTOs können eine Liste von Links für HATEOAS haben . So etwas sollte Persistenzobjekten nicht hinzugefügt werden. Wenn Sie Spring HATEOAS verwenden , können Sie Ihre DTO-Klassen erweitern
RepresentationModel
(früher bekannt alsResourceSupport
) oder mitEntityModel
(früher bekannt alsResource<T>
) umschließen .Umgang mit dem Boilerplate-Code
Sie müssen Ihre Persistenzentitäten nicht manuell DTOs zuordnen und umgekehrt . Es gibt viele Mapping-Frameworks, mit denen Sie dies tun können. Schauen Sie sich beispielsweise MapStruct an , das auf Anmerkungen basiert und als Maven-Anmerkungsprozessor arbeitet. Es funktioniert sowohl in CDI- als auch in Spring-basierten Anwendungen.
Sie können auch wollen betrachten Lombok Getter, Setter, zu erzeugen
equals()
,hashcode()
undtoString()
Methoden für Sie.Verwandte Themen: Um Ihren DTO-Klassen bessere Namen zu geben, lesen Sie diese Antwort .
quelle
Wenn Ihre API öffentlich ist und Sie mehrere Versionen unterstützen müssen, müssen Sie sich für DTOs entscheiden.
Wenn es sich jedoch um eine private API handelt und Sie sowohl den Client als auch den Server steuern, überspringe ich in der Regel die DTOs und mache das Domänenmodell direkt verfügbar.
quelle
Ich neige dazu, DTOs zu verwenden.
Ich mag die Nachteile nicht, aber es scheint, dass die anderen Optionen noch schlimmer sind:
Das Aussetzen von Domänenobjekten kann zu Sicherheitsproblemen und Datenlecks führen. Jackson-Anmerkungen scheinen das Problem zu lösen, aber es ist zu einfach, einen Fehler zu machen und Daten offenzulegen, die nicht offengelegt werden sollten. Beim Entwerfen einer DTO-Klasse ist es viel schwieriger, einen solchen Fehler zu machen.
Auf der anderen Seite können die Nachteile des DTO-Ansatzes durch Dinge wie Objekt-zu-Objekt-Zuordnung und Lombok für weniger Boilerplate reduziert werden .
quelle
Wie Sie bereits selbst festgestellt haben, handelt es sich eindeutig um eine meinungsbezogene Frage. Ich selbst bin mehr vom No-DTO-Ansatz angezogen, einfach wegen des gesamten Boilerplate-Codes, den Sie benötigen.
Dies gilt hauptsächlich für die Antwortseite einer JSON / Rest-API. Ich habe sogar ein Jackson-Addon geschrieben, um zu vermeiden, dass für diese Fälle viele JSON-Ansichten / Filter geschrieben werden: https://github.com/Antibrumm/jackson-antpathfilter
Andererseits sind DTOs eine gute Sache auf der Anforderungseingabeseite solcher APIs. Die direkte Arbeit an Entitäten kann sehr schwierig sein, wenn beispielsweise bidirektionale Beziehungen berücksichtigt werden. Außerdem möchten Sie nicht, dass ein Anrufer beispielsweise ein "Ersteller" -Attribut ändert. Daher müssten Sie bestimmte Felder während der Zuordnung solcher Anforderungen nicht zulassen.
quelle