28-3 Modification (Update)
Prochain arrêt, être en mesure de modifier des événements via l'API!
Coquille Contrôleur/Service/Repository
Pour procéder à une modification d'événement, le contrôleur d'API recevra la requête HTTP à traiter, appellera ensuite le service EvenementService qui pour sa part appellera la couche de données via EvenementRepository pour procéder à la sauvegarde.
DTO - ModifierEvenementDto
Pour la modification, techniquement la modification pourrait être partielle. Nous pourrions modifier seulement le nom, par exemple. Ainsi, les propriétés doivent être optionnelles.
- Sous le dossier
Snowfall.Application/Dtos/Evenements, créez un fichierModifierEvenementDto - Mettez les propriétés optionnelles
Snowfall.Application/Dtos/Evenements/ModifierEvenementDto.cs
public class ModifierEvenementDto
{
public string? Nom { get; set; } = null!;
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; }
}
Contrôleur - EvenementsController#Update
Pour créer un événement via l'API, il sera nécessaire d'avoir une action d'API répondant à la méthode HTTP PATCH et recevant en paramètre EvenementDto, en plus du id de l'événement à modifier. Ce dernier provient de la route.
/// <summary>
/// PATCH /api/evenements/{id}
/// Permets de modifier un événement
/// </summary>
/// <param name="id">Le id de l'événement à modifier</param>
/// <param name="modifierEvenementDto">Le DTO de l'événement modifié à sauvegarder</param>
/// <returns></returns>
[HttpPatch("{id:int}")]
public async Task<IActionResult> Update(int id, ModifierEvenementDto modifierEvenementDto)
{
throw new NotImplementedException();
}
Repository - EvenementRepository#Update
Dans un second temps, ajoutons à l'interface du repository la fonction Update qui prend en paramètre un événement et retourne si la modification a été un succès.
public interface IEvenementRepository
{
Task<List<Evenement>> GetAll();
Task<List<Evenement>> FindByVilleId(int villeId);
Task<Evenement?> FindById(int id);
Task<Evenement> Create(Evenement evenement);
Task<bool> Update(Evenement evenement);
}
Ensuite, il est possible de faire Implement missing members à partir de l'aide contextuelle de Rider dans la classe EvenementRepository. Cela ajoutera la fonction Update à l'implémentation du repository.
public async Task<bool> Update(Evenement evenement)
{
throw new NotImplementedException();
}
Vous devez implémenter vous-même le détail de la fonction de modification du repository, soit la modification dans la base de données. Vous pouvez vous baser sur la fonction de modification de question.
Service - EvenementService#Create
Finalement, dans l'interface IEvenementService, on ajoute la fonction Update:
public interface IEvenementService
{
Task<List<Evenement>> GetAll();
Task<List<Evenement>> FindByVilleId(int? villeId);
Task<Evenement?> FindById(int id);
Task<Evenement> Create(Evenement evenement);
Task<bool> Update(Evenement evenement);
}
Pour ensuite implémenter via Implement missing members la fonction dans EvenementService et appeler le repository.
public async Task<bool> Update(Evenement evenement)
{
return await _evenementRepository.Update(evenement);
}
Compléter EvenementController#Update
Si vous avez complété la requête SQL au niveau du repository pour la mise à jour, nous avons tous les éléments en place pour compléter la fonction Update du contrôleur d'événements.
-
Premièrement, on récupère l'événement pour vérifier qu'il existe bien.
Snowfall.Web.Api/Controllers/EvenementsController.cs[HttpPatch("{id:int}")]
public async Task<IActionResult> Update(int id, ModifierEvenementDto modifierEvenementDto)
{
var evenement = await _evenementService.FindById(id);
if (evenement == null)
return NotFound();
} -
Ensuite, on
maple DTO reçu enEvenementpour être en mesure d'envoyer le tout à la coucheService. Par contre,AutoMapperne sera pas d'une grande aide ici :(attentionAutoMapper est peu adapté aux mises à jour partielles avec des champs optionnels. Recevoir une mise à jour qui ne mettrais à jour que le
nomde l'événement aurait pour conséquence de remplacer le reste des champs par des valeursnullou encore0dans le cas d'un int.Bref, on fera l'association manuellement 😬
Snowfall.Web.Api/Controllers/EvenementsController.cs[HttpPatch("{id:int}")]
public async Task<IActionResult> Update(int id, ModifierEvenementDto modifierEvenementDto)
{
var evenement = await _evenementService.FindById(id);
if (evenement == null)
return NotFound();
if (modifierEvenementDto.VilleId != null) evenement.VilleId = modifierEvenementDto.VilleId.Value;
if (modifierEvenementDto.Description != null) evenement.Description = modifierEvenementDto.Description;
if (modifierEvenementDto.Nom != null) evenement.Nom = modifierEvenementDto.Nom;
if (modifierEvenementDto.ImagePath != null) evenement.ImagePath = modifierEvenementDto.ImagePath;
if (modifierEvenementDto.Date != null) evenement.Date = modifierEvenementDto.Date.Value;
if (modifierEvenementDto.Capacite != null) evenement.Capacite = modifierEvenementDto.Capacite.Value;
if (modifierEvenementDto.Prix != null) evenement.Prix = modifierEvenementDto.Prix.Value;
}Tout ça ajoute beaucoup de lignes au contrôleur cependant. C'est pourquoi je vous suggère d'ajouter une méthode d'extension sur le type
ModifierEvenementDtoafin de faire le mappage dans une fonction dédiée. -
Créez un dossier
Mappingssous le projetApplication -
Créez une classe
EvenementMappingExtensionssous ce nouveau dossierMappings -
Faites de la classe une classe
staticet ajoutez une fonctionApplyToSnowfall.Application/Mappings/EvenementMappingExtensions.cspublic static class EvenementMappingExtensions
{
public static void ApplyTo(this ModifierEvenementDto src, Evenement dest)
{
}
}infoOn se rappelle que les méthodes d'extension doivent être dans une clase static.
Ensuite, on remarque que la fonction
ApplyTosera ajoutée au typeModifierEvenementDto. La fonction fera la conversion entreModifierEvenementDto(src) etEvenement(dest). -
Copiez votre mapping dans cette fonction.
Snowfall.Application/Mappings/EvenementMappingExtensions.cspublic static class EvenementMappingExtensions
{
public static void ApplyTo(this ModifierEvenementDto src, Evenement dest)
{
if (src.VilleId != null) dest.VilleId = src.VilleId.Value;
if (src.Description != null) dest.Description = src.Description;
if (src.Nom != null) dest.Nom = src.Nom;
if (src.ImagePath != null) dest.ImagePath = src.ImagePath;
if (src.Date != null) dest.Date = src.Date.Value;
if (src.Capacite != null) dest.Capacite = src.Capacite.Value;
if (src.Prix != null) dest.Prix = src.Prix.Value;
}
}infoAssurez-vous de remplacer
modifierEvenementDtoparsrcetevenementpardest.Vous pouvez utiliser la fonction
Refactor->Renamede Rider. -
Appelez
ApplyTodans le contrôleurSnowfall.Web.Api/Controllers/EvenementsController.cs[HttpPatch("{id:int}")]
public async Task<IActionResult> Update(int id, ModifierEvenementDto modifierEvenementDto)
{
var evenement = await _evenementService.FindById(id);
if (evenement == null)
return NotFound();
modifierEvenementDto.ApplyTo(evenement);
}Beaucoup plus propre! :)
-
On procède finalement à la mise à jour via le service. Dans le cas où le résultat serait
false, et donc que la mise à jour n'a pas été un succès, on retournera le code d'erreur422 Unprocessable Content. Ce code d'erreur stipule que le serveur a reçu la requête, qu'elle est valide, mais pour une raison quelconque n'a pas pu traiter la requête correctement.Snowfall.Web.Api/Controllers/EvenementsController.cs[HttpPatch("{id:int}")]
public async Task<IActionResult> Update(int id, ModifierEvenementDto modifierEvenementDto)
{
var evenement = await _evenementService.FindById(id);
if (evenement == null)
return NotFound();
modifierEvenementDto.ApplyTo(evenement);
bool updated = await _evenementService.Update(evenement);
if (!updated)
return UnprocessableEntity();
} -
Ensuite, on map à nouveau l'événement en un
EvenementDtodans le but de le retourner.Snowfall.Web.Api/Controllers/EvenementsController.cs[HttpPatch("{id:int}")]
public async Task<IActionResult> Update(int id, ModifierEvenementDto modifierEvenementDto)
{
var evenement = await _evenementService.FindById(id);
if (evenement == null)
return NotFound();
modifierEvenementDto.ApplyTo(evenement);
bool updated = await _evenementService.Update(evenement);
if (!updated)
return UnprocessableEntity();
return Ok(_mapper.Map<EvenementDto>(evenement));
}
Tester via Postman ou Scalar
Assurez-vous d'avoir implémenté la fonction de modification Update du repository!
Pour tester, vous pouvez utiliser Postman.
- Assurez-vous que votre projet .NET est démarré et recompilé pour contenir les derniers changements
- Assurez-vous de choisir
PATCHcomme méthodeHTTP - Entrez comme URL http://[url-de-votre-projet]/api/evenements/[id-evenement]
- Sélectionner
Body/raw/JSONet entrer leJSONmodifié pour modifier l'événement souhaité.
Pour obtenir un JSON d'événement à modifier, faites premièrement une requête GET vers l'événement à modifier.
Vous recevrez la version actuelle de cet événement que vous pourrez ensuite utiliser comme base pour la modification!

Procédez ensuite à la requête de modification:
