24-2 Le retour des DTO
On expose que très rarement le contenu entier d'une entité provenant de la base de données.
En effet, le retour d'un API est "publiquement" accessible. En utilisant les outils développeur du navigateur, on peut inspecter les requêtes réseau et obtenir le résultat de l'API.
Et s'il y avait un champ qu'on ne veut pas exposer via l'API? Le cas évident est le hash de mot de passe d'un utilisateur, par exemple, ou autres informations sensibles.
Et même si ce n'est pas le cas dans l'immédiat, un développeur peut ajouter une colonne "sensible" à un modèle et puisque le modèle est retourné directement de l'API, automatiquement cette nouvelle donnée sensible se retrouvera être retournée.
Pour pallier à cette situation, nous avons vu en Web 3 le concept de DTO (Data Transfer Object). Ils sont utilisés pour échanger de l'information entre un client (Blazor dans le navigateur par exemple) et un serveur (l'API).
Les DTO sont essentiellement des conteneurs de données et n'ont généralement pas de logique ou de comportement.
Ils sont des objets simples utilisés pour transférer des données entre différentes couches d'une application. Ils favorisent la séparation des responsabilités et la modularité.
Créer le DTO EvenementDto
Plutôt que de retourner une liste d'événements via l'API, on retournera une liste de EvenementDto
. C'est un peu l'équivalent du ViewModel
, mais appliqué à l'API.
Les DTO
appartiennent à la couche Application
puisqu'ils sont partis des particularités de notre implémentation logicielle.
- Sous le projet
Snowfall.Application
->Clic droit
->Add
->Directory
- Nommez le dossier
Dtos
- Sous le dossier
Dtos
->Clic droit
->Add
->Directory
- Nommez le dossier
Evenements
- Sous le dossier
Dtos/Evenements
->Clic droit
->Add
->Class/Interface
- Nommez la classe
EvenementDto
- Mettez-y une implémentation de base qui correspond à la définition d'un événement:
Snowfall.Application/Dtos/Evenements/EvenementDto.cs
public class EvenementDto
{
public int Id { get; set; }
public string Nom { get; set; }
public string? Description { get; set; }
public string? ImagePath { get; set; }
public DateTime Date { get; set; }
public Decimal Prix { get; set; }
public int Capacite { get; set; }
public int VilleId { get; set; }
}
Retourner un DTO
Comment est-ce qu'on retourne une liste de EvenementDto
plutôt qu'une liste de Evenement
, alors que le service retourne des Evenement
?
Peut-être pourrait-on caster
la liste en une liste de type EvenementDto
?
public async Task<IActionResult> Index()
{
List<Evenement> evenements = await _evenementService.GetAll();
// ??
return Ok((List<EvenementDto>)evenements);
}
Le compilateur n'aime pas vraiment cette approche et nous informe qu'il est impossible d'effectuer cette opération.
Pourquoi pas itérer au travers de la liste d'Evenement
et pour chacun, créer un EvenementDto
correspondant pour finalement l'ajouter à une liste de EvenementDto
?
Quelque chose comme ceci:
public async Task<IActionResult> Index()
{
List<Evenement> evenements = await _evenementService.GetAll();
List<EvenementDto> evenementDtos = new List<EvenementDto>();
foreach (var evenement in evenements)
{
evenementDtos.Add(new EvenementDto
{
Id = evenement.Id,
Capacite = evenement.Capacite,
Date = evenement.Date,
Description = evenement.Description,
ImagePath = evenement.ImagePath,
Nom = evenement.Nom,
Prix = evenement.Prix,
VilleId = evenement.VilleId
});
}
return Ok(evenementDtos);
}
Test
Essayez via Scalar ou Postman, le tout fonctionne, mais ce n'est pas particulièrement élégant et c'est très fastidieux!