Je crée actuellement une API REST pour un projet et j'ai lu article sur article sur les meilleures pratiques. Beaucoup semblent être contre les DTO et ne font qu'exposer le modèle de domaine, tandis que d'autres semblent penser que les DTO (ou les modèles utilisateur ou tout ce que vous voulez appeler) sont une mauvaise pratique. Personnellement, je pensais que cet article avait beaucoup de sens.
Cependant, je comprends également les inconvénients des DTO avec tout le code de mappage supplémentaire, des modèles de domaine qui pourraient être 100% identiques à leur homologue DTO, etc.
Notre API est principalement créée pour que d'autres clients puissent consommer des données, mais si nous le faisons correctement, nous aimerions également l'utiliser pour notre propre interface graphique Web si possible.
Le fait est que nous ne souhaitons peut-être pas exposer toutes les données du domaine aux autres utilisateurs clients. La plupart des données n'auront de sens que dans notre propre application Web. En outre, nous pouvons ne pas souhaiter exposer toutes les données sur un objet dans tous les scénarios, en particulier les relations avec d'autres objets, etc. Par exemple, si nous exposons une liste d'un objet particulier, nous ne voudrions pas nécessairement exposer toute la hiérarchie d'objets; afin que les enfants de l'objet ne soient pas exposés, mais puissent être découverts via des liens (hateoas).
Comment dois-je résoudre ce problème? Je pensais utiliser les mixins de Jackson sur nos modèles de domaine pour contrôler quelles données seraient exposées dans différents scénarios. Ou devrions-nous simplement utiliser les DTO à fond - même compte tenu de ses inconvénients et de sa controverse?
Réponses:
Pourquoi vous devriez utiliser les DTO dans votre API REST
DTO signifie D ata T ransfert O bjet .
Ce modèle a été créé avec un objectif très bien défini: transférer des données vers des interfaces distantes , tout comme les services Web . Ce modèle s'intègre très bien dans une API REST et les DTO vous donneront plus de flexibilité à long terme.
Les modèles qui représentent le domaine de votre application et les modèles qui représentent les données gérées par votre API sont (ou devraient au moins être) des préoccupations différentes et doivent être découplés les uns des autres. Vous ne souhaitez pas casser vos clients API lorsque vous ajoutez, supprimez ou renommez un champ du modèle de domaine d'application.
Alors que votre couche de service fonctionne sur les modèles de domaine / de persistance, vos contrôleurs d'API doivent fonctionner sur un ensemble différent de modèles. Au fur et à mesure que vos modèles de domaine / de persistance évoluent pour prendre en charge de nouvelles exigences commerciales, par exemple, vous souhaiterez peut-être créer de nouvelles versions des modèles d'API pour prendre en charge ces changements. Vous pouvez également désapprouver les anciennes versions de votre API à mesure que de nouvelles versions sont publiées. Et il est parfaitement possible de le réaliser lorsque les choses sont découplées.
Juste pour mentionner quelques avantages de l'exposition des DTO au lieu des modèles de persistance:
Découplez les modèles de persistance des modèles d'API.
Les DTO peuvent être adaptés à vos besoins et ils sont parfaits lorsqu'ils n'exposent qu'un ensemble d'attributs de vos entités de persistance. Vous n'aurez pas besoin d'annotations telles que
@XmlTransient
et@JsonIgnore
pour éviter la sérialisation de certains attributs.En utilisant les DTO, vous éviterez un enfer d'annotations dans vos entités de persistance, c'est-à-dire que vos entités de persistance ne seront pas gonflées d'annotations non liées à la persistance.
Vous aurez un contrôle total sur les attributs que vous recevez lors de la création ou de la mise à jour d'une ressource.
Si vous utilisez Swagger , vous pouvez utiliser
@ApiModel
et@ApiModelProperty
annotations pour documenter vos modèles API sans déconner vos entités de persistance.Vous pouvez avoir différents DTO pour chaque version de votre API.
Vous aurez plus de flexibilité lors de la cartographie des relations.
Vous pouvez avoir différents DTO pour différents types de supports.
Vos DTO peuvent avoir une liste de liens pour HATEOAS . C'est le genre de chose qui ne devrait pas être ajoutée aux objets de persistance. Lorsque vous utilisez Spring HATEOAS , vous pouvez étendre vos classes DTO
RepresentationModel
(anciennement appeléesResourceSupport
) ou les encapsuler avecEntityModel
(anciennement appeléeResource<T>
).Traitement du code standard
Vous n'aurez pas besoin de mapper manuellement vos entités de persistance aux DTO et vice versa . Il existe de nombreux cadres de cartographie que vous pouvez utiliser pour le faire. Par exemple, jetez un œil à MapStruct , qui est basé sur les annotations et fonctionne comme un processeur d'annotation Maven. Cela fonctionne bien dans les applications basées sur CDI et Spring.
Vous pouvez également envisager de Lombok pour générer des getters, setters,
equals()
,hashcode()
et lestoString()
méthodes pour vous.Connexes: pour donner de meilleurs noms à vos classes DTO, reportez-vous à cette réponse .
la source
Lorsque votre API est publique et que vous devez prendre en charge plusieurs versions, vous devez utiliser les DTO.
D'un autre côté, s'il s'agit d'une API privée et que vous contrôlez à la fois le client et le serveur, j'ai tendance à ignorer les DTO et à exposer directement le modèle de domaine.
la source
J'ai tendance à utiliser des DTO.
Je n'aime pas les inconvénients mais il semble que les autres options sont encore pires:
L'exposition d'objets de domaine peut entraîner des problèmes de sécurité et des fuites de données. Les annotations Jackson peuvent sembler résoudre le problème, mais il est trop facile de se tromper et d'exposer des données qui ne devraient pas être exposées. Lors de la conception d'une classe DTO, il est beaucoup plus difficile de faire une telle erreur.
D'un autre côté, les inconvénients de l'approche DTO peuvent être réduits avec des choses comme le mappage objet à objet et Lombok pour moins de passe-partout.
la source
Comme vous l'avez déjà dit, il s'agit clairement d'une question d'opinion. Je suis moi-même plus attiré par l'approche No-DTO, simplement à cause de tout le code standard dont vous avez besoin.
Ceci est principalement vrai pour le côté réponse d'une API json / rest. J'ai même écrit un addon jackson pour éviter d'écrire de nombreuses vues / filtres json pour ces cas: https://github.com/Antibrumm/jackson-antpathfilter
D'un autre côté, les DTO sont une bonne chose du côté de l'entrée de demande de ces API. Travailler directement sur des entités peut être assez difficile en tenant compte des relations bidirectionnelles par exemple. De plus, vous ne voulez pas vraiment laisser un appelant modifier un attribut "créateur" par exemple. Vous devrez donc interdire certains champs lors du mappage de telles demandes.
la source