Aller au contenu principal

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.

  1. Sous le dossier Snowfall.Application/Dtos/Evenements, créez un fichier ModifierEvenementDto
  2. 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.

Snowfall.Web.Api/Controllers/EvenementsController.cs
/// <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.

Snowfall.Data/Repositories/IEvenementRepository.cs
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.

Snowfall.Data/Repositories/EvenementRepository.cs
public async Task<bool> Update(Evenement evenement)
{
throw new NotImplementedException();
}
attention

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:

Snowfall.Application/Services/IEvenementService.cs
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.

Snowfall.Application/Services/EvenementService.cs
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.

  1. 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();
    }
  2. Ensuite, on map le DTO reçu en Evenement pour être en mesure d'envoyer le tout à la couche Service. Par contre, AutoMapper ne sera pas d'une grande aide ici :(

    attention

    AutoMapper est peu adapté aux mises à jour partielles avec des champs optionnels. Recevoir une mise à jour qui ne mettrais à jour que le nom de l'événement aurait pour conséquence de remplacer le reste des champs par des valeurs null ou encore 0 dans 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 ModifierEvenementDto afin de faire le mappage dans une fonction dédiée.

  3. Créez un dossier Mappings sous le projet Application

  4. Créez une classe EvenementMappingExtensions sous ce nouveau dossier Mappings

  5. Faites de la classe une classe static et ajoutez une fonction ApplyTo

    Snowfall.Application/Mappings/EvenementMappingExtensions.cs
    public static class EvenementMappingExtensions
    {
    public static void ApplyTo(this ModifierEvenementDto src, Evenement dest)
    {

    }
    }
    info

    On se rappelle que les méthodes d'extension doivent être dans une clase static.

    Ensuite, on remarque que la fonction ApplyTo sera ajoutée au type ModifierEvenementDto. La fonction fera la conversion entre ModifierEvenementDto (src) et Evenement (dest).

  6. Copiez votre mapping dans cette fonction.

    Snowfall.Application/Mappings/EvenementMappingExtensions.cs
    public 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;

    }
    }
    info

    Assurez-vous de remplacer modifierEvenementDto par src et evenement par dest.

    Vous pouvez utiliser la fonction Refactor -> Rename de Rider.

  7. Appelez ApplyTo dans le contrôleur

    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);
    }

    Beaucoup plus propre! :)

  8. 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'erreur 422 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();
    }
  9. Ensuite, on map à nouveau l'événement en un EvenementDto dans 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

attention

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 PATCH comme méthode HTTP
  • Entrez comme URL http://[url-de-votre-projet]/api/evenements/[id-evenement]
  • Sélectionner Body/raw/JSON et entrer le JSON modifié pour modifier l'événement souhaité.
astuce

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!

Imgur

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

Imgur