web-dev-qa-db-fra.com

REST API - DTO ou pas?

Je suis en train de créer une API REST pour un projet et je lis article sur article sur les meilleures pratiques. Beaucoup semblent être contre les DTO et simplement exposer le modèle de domaine, alors que d'autres semblent penser que les DTO (ou les modèles d'utilisateur ou ce que vous voulez appeler) sont une mauvaise pratique. Personnellement, je pensais que cet article avait beaucoup de sens.

Cependant, je comprends aussi les inconvénients des DTO avec tout le code de mappage supplémentaire, des modèles de domaine qui pourraient être identiques à 100% à leur équivalent DTO, etc.

Notre API est principalement créée pour que d'autres clients puissent utiliser des données. Toutefois, si nous le faisons correctement, nous aimerions également l'utiliser si possible pour notre propre interface graphique Web.

Le fait est que nous ne souhaitons peut-être pas exposer toutes les données du domaine aux autres utilisateurs du client. Une grande partie des données n’aura de sens que dans notre propre application Web. En outre, nous ne souhaitons peut-être pas exposer toutes les données relatives à 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 des objets. afin que les enfants de l'objet ne soient pas exposés, mais puissent être découverts à travers des liens (hateoas).

Comment dois-je résoudre ce problème? Je pensais utiliser des mixins Jackson sur nos modèles de domaine pour contrôler les données qui seraient exposées selon différents scénarios. Ou devrions-nous simplement utiliser les DTO jusqu'au bout, même en raison de ses inconvénients et de sa controverse?

126
benbjo

Pourquoi utiliser des DTO dans votre API REST

DTO signifie D ata T transfert O bject .

Ce modèle a été créé dans un but bien défini: transférer des données vers des interfaces distantes , exactement comme 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 représentant le domaine de votre application et les modèles représentant les données gérées par votre API sont (ou au moins devraient be) diffère et devrait être découplé 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/persistance, vos contrôleurs d'API doivent fonctionner sur un ensemble de modèles différent. Au fur et à mesure que vos modèles de domaine/persistance évoluent pour prendre en charge de nouvelles exigences métier, vous pouvez par exemple créer de nouvelles versions des modèles d'API pour prendre en charge ces modifications. Vous pouvez également désapprouver les anciennes versions de votre API lorsque de nouvelles versions sont publiées. Et il est parfaitement possible d’atteindre le résultat escompté.


Pour ne citer que quelques avantages d’exposer des DTO au lieu de modèles de persistance:

  • Découple les modèles de persistance des modèles d'API.

  • Les DTO peuvent être adaptés à vos besoins et sont parfaits pour exposer uniquement 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 des 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 surchargées avec des 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 d'API sans perturber votre entités de persistance.

  • Vous pouvez avoir différents DTO pour chaque version de votre API.

  • Vous aurez plus de flexibilité lors du mappage des relations.

  • Vous pouvez avoir différents DTO pour différents types de média.

  • Vos DTO peuvent avoir une liste de liens pour HATEOAS . C'est le genre de chose qui ne devrait pas être ajouté aux objets de persistance. Lorsque vous utilisez Spring HATEOAS , vous pouvez étendre vos classes DTO ResourceSupport ou les envelopper de Resource<T> .

Traiter avec le code standard

Vous n'aurez pas besoin de mapper vos entités de persistance sur des DTO et vice versa manuellement . Il y a plusieurs frameworks de mapping vous pouvez utiliser pour le faire. Par exemple, jetez un oeil à MapStruct , qui est basé sur les annotations et fonctionne comme un processeur d'annotation Maven. Cela fonctionne bien dans les applications CDI et Spring.

Vous pouvez également envisager d’utiliser la méthode Lombok pour générer des méthodes d’affectation, de réglage, equals(), hashcode() et toString().


Connexes: Pour donner de meilleurs noms à vos classes DTO, reportez-vous à ceci réponse .

200
cassiomolin

Lorsque votre API est publique et que vous devez prendre en charge plusieurs versions, vous devez utiliser des DTO.

D'autre part, 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.

20
David Siro

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 une fuite de données. Les annotations de Jackson peuvent sembler résoudre le problème, mais il est trop facile de se tromper et d’exposer des données qui ne doivent pas être exposées. Lors de la conception d'une classe DTO, il est beaucoup plus difficile de commettre une telle erreur.

D'un autre côté, les inconvénients de l'approche DTO peuvent être réduits avec des éléments tels que la cartographie d'objet à objet et Lombok pour moins de passe-passe.

11
Argb32

Comme vous l'avez déjà dit vous-même, 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 beaucoup de vues/filtres json pour ces cas: https://github.com/Antibrumm/jackson-antpathfilter

D'autre part, les DTO sont une bonne chose du côté de la saisie de requête de telles API. Travailler directement sur des entités peut être assez difficile en prenant en compte les relations bidirectionnelles par exemple. Aussi, vous ne voulez pas vraiment laisser un appelant modifier un attribut "créateur" par exemple. Il vous faudra donc dissocier certains champs lors du mappage de telles demandes.

6
Martin Frey