API REST - DTO ou pas? [fermé]

154

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?

benbjo
la source
9
Ne soyez pas surpris si cette question se ferme. C'est plus une question basée sur la discussion, ce qui signifie qu'il n'y a pas de réponse claire et correcte. Demandez à différentes personnes et vous obtiendrez une réponse différente.
Ben Thurley
2
Ce lien d'article ( ibm.com/developerworks/community/blogs/barcia/entry/… ) est rompu.
pinkpanther
7
@pinkpanther C'est un excellent article et c'est dommage qu'il ne soit plus disponible. Voici la version mise en cache de Web Archive .
cassiomoline

Réponses:

252

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 @XmlTransientet @JsonIgnorepour é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 @ApiModelet @ApiModelPropertyannotations 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ées ResourceSupport) ou les encapsuler avec EntityModel(anciennement appelée Resource<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 les toString()méthodes pour vous.


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

cassiomoline
la source
2
Si je suivais la voie DTO, mapperiez-vous tous les objets de domaine à un DTO ou simplement ceux qui ne seraient pas identiques? De plus, comment résoudriez-vous le problème de l'exposition des données en fonction de différents scénarios / contextes? Plusieurs DTO par objet de domaine?
benbjo
6
@benbjo C'est à vous de décider. Je mappe généralement uniquement les entités les plus complexes aux DTO, les entités dont je ne souhaite pas que tous les attributs soient exposés et les entités avec de nombreuses relations. Les DTO me donnent la flexibilité d'avoir une liste de liens à utiliser dans HATEOAS. C'est le genre de chose que je n'ajouterais pas à mes objets de persistance.
cassiomoline
2
@molin merci beaucoup pour les informations et suggestions. Je vais certainement vérifier MapStruct. En un coup d'œil, il semble très bien répondre à mes besoins.
benbjo
6
Cher votant défavorable, pourriez-vous au moins expliquer la raison de votre vote défavorable?
cassiomolin
8
Il existe également une raison architecturale d'utiliser des DTO au lieu d'entités de domaine dans l'API REST. L'API REST ne doit pas changer pour éviter de casser les clients existants. Si vous utilisez le modèle de domaine directement dans l'API, vous créez un couplage indésirable entre l'API et le modèle de domaine. Selon le principe de conception du couplage lâche de service, le contrat de service ne doit pas être étroitement lié à la logique de service ou aux détails de mise en œuvre.
Paulo Merson
25

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.

David Siro
la source
Je suis d'accord avec vous sur la dernière partie et je le fais généralement, mais c'est ma première API publique. Je vais considérer ce que vous dites sur l'utilisation des DTO pour la partie publique. Peut-être que les parties privées et publiques de l'API devraient en effet être séparées, même si «manger votre propre dogfood» est un bon principe.
benbjo
11

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.

Argb32
la source
9

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.

Martin Frey
la source
2
Je suis d'accord que ma question est quelque peu liée à l'opinion (et déconseillée), mais je cherchais également des conseils sur la façon de résoudre mon problème. Je vais en prendre beaucoup à votre addon Jackson, mais pensez-vous que l'utilisation de mixins pour contrôler quelles données doivent être exposées dans différentes scènes est une bonne chose à faire?
benbjo