"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Que peut-il arriver si vous ignorez les DTO

Que peut-il arriver si vous ignorez les DTO

Publié le 2024-08-02
Parcourir:839

What can happen if you skip the DTOs

C'est bien qu'un framework comme SpringBoot puisse faire autant de choses pour vous.

Vous avez juste besoin d'une classe d'entité JPA et d'une interface de référentiel simple et SpringData vous offre tout ce dont vous avez besoin pour les opérations de base de données CRUD typiques.

Vous écrivez une classe de contrôleur REST simple et vous avez une API REST en cours d'exécution, n'est-ce pas ?

Hé, mais tu as oublié d'écrire un DTO ! Mais pourquoi en avez-vous réellement besoin alors que votre application pourrait fonctionner sans lui ?

Il y a certainement quelques raisons générales :

  • structure en couches (par exemple, architecture hexagonale ou ports et adaptateurs) : pour des raisons de maintenabilité, il est judicieux de découpler le code de communication externe du noyau (logique métier)
  • sécurité et performances : si vous exposez la structure de la base de données dans votre API telle quelle, vous arriverez bientôt à un point où vous en exposerez plus que nécessaire ; qui peuvent être utilisés à mauvais escient par des acteurs malveillants ou gaspiller des ressources (CPU, mémoire et bande passante réseau)
  • Les DTO, contrairement aux entités JPA, peuvent être immuables (vous pouvez utiliser des enregistrements Java) et c'est bon pour le style de programmation (fonctionnel) basé sur les données, les tests unitaires agréables, la concurrence plus sûre, etc.

Mais d'autres choses étranges peuvent aussi arriver. Je vais vous montrer un exemple étrange basé sur mon expérience.

Ce dépôt GitHub contient une application simple qui fonctionne sans les DTO. Il existe une entité utilisateur, chaque utilisateur peut avoir plusieurs transactions. Nous avons même un bean Service entre le référentiel et le RestController, interceptant d'éventuelles exceptions d'accès à la base de données.

Comme nous voulons créer une application prête pour la production, nous ne voulons pas qu'Hibernate génère le DDL. Au lieu de cela, nous avons un schema.sql qui crée les tables (plus tard, nous pourrons passer à Flyway ou Liquibase). Pour notre exemple simple, nous avons également un data.sql pour que nos tables ne soient pas vides.

Lorsque nous exécutons l'application et appelons le point de terminaison de l'API à l'adresse http://localhost:8080/users, nous obtenons le JSON attendu contenant les utilisateurs et leurs transactions.

Façons maintenant attention aux deux lignes de code de la classe Transaction, marquées //!!

@JsonIgnorer //!!

La première odeur est que dans la classe Transaction, nous avons dû ajouter l'annotation @JsonIgnore à la référence User. Sans cette annotation, la sérialisation JSON plante en raison d'une récursivité infinie.

Imaginons maintenant que quelqu'un fasse une erreur en ajoutant un autre champ (description) à l'entité Transaction, mais oublie d'ajuster les instructions SQL (ou exécute l'application dans un environnement où la modification de schéma n'a pas été appliquée).

description de la chaîne privée ;//!!

Bien sûr, l'appel API échoue désormais. Mais regardez la gestion des erreurs ! La clause catch à l'intérieur du UserService ne fonctionne pas comme prévu. Au lieu de cela, nous pouvons voir une étrange trace de pile dans le journal :
GlobalExceptionHandler : erreur inattendue org.springframework.http.converter.HttpMessageNotWritableException : impossible d'écrire JSON : 

J'ai vu une fois cette situation (clairement, avec une application beaucoup plus grande que cet exemple) et il m'a fallu un certain temps pour comprendre pourquoi l'exception SQL a échappé au service et pourquoi j'obtenais une HttpMessageNotWritableException. Peux-tu le voir?

Ce qui se passe, c'est que la classe UserService (via UserRepository) interroge uniquement la table de base de données USERS. Les entités Transaction ne font pas partie du résultat en raison du chargement différé par défaut d'Hibernate. Ce n'est que lorsque le désérialiseur Jackson tente de créer du JSON à partir de l'instance User qu'il invoque sa méthode getTransactions qui permet à Hibernate de récupérer les entités Transaction.

C'est pourquoi nous obtenons une étrange trace de pile combinant des éléments JSON et SQL. L'exception est interceptée par le GlobalExceptionHandler qui ne sait pas quoi en faire, c'est pourquoi le message du journal est "Erreur inattendue".

J'espère que ce petit exercice vous fera comprendre plus profondément à quel point il est dangereux de permettre aux différentes couches de votre application de se mélanger. Ne voir que les scénarios de « journée ensoleillée » de votre application alors qu'elle est encore petite peut amener certains développeurs à continuer de faire la mauvaise chose jusqu'à ce qu'il soit trop tard.

Vous n'avez pas besoin d'écrire le code passe-partout mappant les champs entre votre DTO et les autres couches de votre application. MapStruct peut le faire pour vous.

Déclaration de sortie Cet article est reproduit sur : https://dev.to/marianvarga/what-can-happen-if-you-skip-the-dtos-aaj?1 En cas de violation, veuillez contacter [email protected] pour supprimer il
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3