Bonjour ! Dans la leçon précédente, nous avons construit une API REST fonctionnelle avec des opérations CRUD complètes. Cependant, comme nous l'avons noté, nous avons pris un raccourci en exposant directement nos entités JPA (Produit) au client. C'est une pratique risquée dans des projets réels.
Aujourd'hui, nous allons corriger cela et adopter une approche beaucoup plus robuste et professionnelle. L'objectif est d'apprendre à utiliser les DTOs (Data Transfer Objects) et MapStruct pour découpler la couche de persistance de l'API. Ce découplage est fondamental pour créer des API sécurisées, maintenables et flexibles.
Nous verrons :
- Pourquoi l'exposition des entités est un problème.
- Comment utiliser les DTOs pour créer un "contrat" d'API stable.
- Comment implémenter un mapping manuel entre Entité et DTO.
- Comment automatiser ce mapping avec MapStruct pour gagner en productivité et en fiabilité.
1. Le problème : Couplage entre l'API et la base de données
Lorsque votre contrôleur retourne directement une entité JPA, vous créez un lien direct entre la structure de votre base de données et ce que le client de votre API reçoit.
Pourquoi ce couplage est-il dangereux ?
- Sécurité : Vous risquez d'exposer des données sensibles qui ne devraient jamais quitter le serveur, comme des mots de passe hachés, des informations personnelles ou des champs techniques (
createdAt,version, etc.). - Flexibilité : Le moindre changement dans votre entité (renommer un champ, en ajouter un) peut casser les clients de votre API. L'API devient fragile.
- Optimisation : L'entité n'est pas toujours la représentation idéale des données pour le client. Parfois, vous voulez combiner des informations de plusieurs entités, calculer un champ, ou "aplatir" une structure d'objets imbriqués.
Pour comprendre ce problème de manière concrète, regardons une courte vidéo qui illustre parfaitement ces risques.
Le Pattern DTO : Cas pratique sur une Application Spring Boot
La vidéo "Le Pattern DTO : Cas pratique sur une Application Spring Boot" de la chaîne Coding With Armand expose clairement le problème. Elle montre une API qui retourne une entité User complète, incluant le mot de passe et un objet Profile imbriqué.
Regardez la vidéo du début jusqu'à 02:16. Concentrez-vous sur : La définition d'un DTO (Data Transfer Object). L'analyse de la réponse JSON dans Postman, qui expose le champ password et une structure imbriquée non désirée.
La solution à ce problème est le Data Transfer Object (DTO). C'est un simple objet dont le seul but est de transporter des données entre les couches de votre application, en particulier entre la couche métier (service) et la couche de présentation (contrôleur).
2. Implémentation manuelle d'un Mapper
Maintenant que nous avons identifié le problème, passons à la solution. Nous allons créer un DTO pour notre ressource et une classe "mapper" qui se chargera de la conversion entre l'entité et le DTO.
Votre expérience avec les "API Resources" dans Laravel vous a déjà familiarisé avec ce concept de couche de transformation. En Java/Spring, le pattern est très similaire.
La suite de la vidéo que vous venez de commencer montre comment implémenter cette solution manuellement.
Le Pattern DTO : Cas pratique sur une Application Spring Boot
Continuons avec la vidéo de Coding With Armand pour voir comment résoudre le problème que nous venons d'identifier. L'auteur va créer un UserDTO, un UserMapperService pour la logique de conversion, et l'intégrer dans le contrôleur.
Regardez la vidéo de 02:16 à 09:25. Observez attentivement les étapes suivantes : Création du UserDTO avec un record Java : notez comment il choisit sélectivement les champs, en omet le mot de passe, et en crée de nouveaux (le name concaténé, l'âge age calculé). Création du UserMapperService : c'est ici que se trouve la logique de transformation. Remarquez le code pour concaténer les noms ou calculer l'âge à partir de la date de naissance. Modification du UserController : le service est injecté et utilisé avec un stream().map() pour transformer la liste d'entités en une liste de DTOs avant de la retourner.
Ce que vous venez de voir est la mise en œuvre complète du pattern DTO :
- Le
Controllerne manipule plus que des DTOs. Il est complètement découplé de l'entité de la base de données. - Le
Serviceorchestre la logique métier et délègue la conversion auMapper. - Le
Mappercentralise toute la logique de transformation, rendant le code plus propre et plus facile à tester.
Le mapping manuel fonctionne, mais il peut vite devenir répétitif et source d'erreurs pour des objets complexes. C'est là qu'intervient MapStruct.
3. Automatisation avec MapStruct
MapStruct est un processeur d'annotations qui génère automatiquement le code de mapping pour vous à la compilation. Il est rapide, prévisible et s'intègre parfaitement avec Spring.

Pour l'utiliser, il suffit de :
- Ajouter les dépendances Maven/Gradle.
- Définir une interface et l'annoter avec
@Mapper. - Déclarer les méthodes de conversion (ex:
ProductResDto toDto(Product product)).
MapStruct générera une implémentation de cette interface pour vous.
L'article suivant fournit un guide pratique et concis pour mettre en place une architecture propre avec Entités, DTOs et un Mapper MapStruct. Il introduit aussi une distinction importante : les DTOs pour les requêtes (entrantes) et les DTOs pour les réponses (sortantes).
Guide : Architecture Microservices avec Spring Boot
L'article "Guide : Architecture Microservices avec Spring Boot" de Soumaila Savadogo montre une implémentation très propre et professionnelle. Il va vous guider dans la mise en place de DTOs et MapStruct.
Prenez environ 15 minutes pour lire attentivement cet article. Concentrez-vous sur les étapes 4, 5 et 7 pour le microservice msProduct. Étape 4 : Créer les DTOs : Comprenez bien la distinction entre ProductReqDto (pour les requêtes POST, sans ID) et ProductResDto (pour les réponses GET, avec ID). Étape 5 : Créer le Mapper (MapStruct) : Analysez l'interface ProductMapper. Notez l'annotation @Mapper(componentModel = "spring") qui permet à Spring de l'injecter comme un bean. Étape 7 : Créer le Service (la partie ProductServiceImp) : Regardez comment le mapper est injecté via le constructeur et utilisé dans les méthodes addProduct et getProductById pour convertir les objets.
L'approche décrite dans cet article est celle que vous devriez viser dans vos projets professionnels. En séparant ReqDto et ResDto, vous gagnez un contrôle encore plus fin sur votre API :
ProductReqDto: Ce que le client est autorisé à envoyer pour créer une ressource. Il ne contient pas de champs générés par le serveur commeidoucreatedAt.ProductResDto: Ce que le serveur choisit de renvoyer au client. C'est la représentation "publique" de votre ressource.
Conclusion
Félicitations ! Vous avez maintenant les clés pour construire des API Spring Boot robustes et découplées, une compétence non négociable sur le marché du travail. Vous êtes passé d'une approche simple mais fragile à une architecture professionnelle qui sépare clairement les préoccupations.
Les points clés à retenir :
- Ne jamais exposer les entités JPA directement dans une API. C'est un risque de sécurité et un frein à la maintenabilité.
- Les DTOs définissent le contrat de votre API. Ils agissent comme une couche d'abstraction entre le client et votre modèle de données interne.
- Utilisez des DTOs distincts pour les requêtes et les réponses (
RequestDTO,ResponseDTO) pour modéliser précisément les données entrantes et sortantes. - La couche Mapper est responsable de la conversion entre Entités et DTOs.
- MapStruct est l'outil de choix pour automatiser la génération de mappers, ce qui réduit le code répétitif et augmente la fiabilité.
Maintenant que nous avons une couche API propre et bien définie grâce aux DTOs, nous pouvons l'enrichir. Dans la prochaine leçon, nous verrons comment mettre en œuvre le filtrage, la recherche et le tri via les paramètres de requête (query parameters). Vous découvrirez comment rendre votre API encore plus puissante et flexible pour les clients qui la consomment.