Passer au contenu du pied de page
Iron Academy Logo
Apprendre le C#
Apprendre le C#

Autres catégories

Ajout d'un point de terminaison DELETE dans .NET Aspire sur Linux

[[academy-video-youtube({"vid": "x10CYBXrLxg", "start_time": "0", "title": "Adding a DELETE Endpoint in .NET Aspire on Linux", "creator": "Tim Corey", "length": "8m 40s"})]]

Chaque API CRUD finit par nécessiter un moyen de supprimer des enregistrements, et le verbe DELETE clôt les quatre opérations HTTP principales aux côtés de GET, POST et PUT. Comparé aux autres verbes, DELETE est structurellement le plus simple : pas de corps de requête, pas de pipeline de validation, pas de type de retour complexe. Ce qu'il introduit cependant est une question de conception qui n'a pas de réponse universellement correcte, à savoir ce qu'il faut renvoyer lorsque l'appelant demande de supprimer un enregistrement qui n'existe pas.

Dans sa vidéo " Ajouter un point de terminaison DELETE dans .NET Aspire sur Linux ", Tim Corey conclut l'API Tiny Ticket en ajoutant le dernier point de terminaison, corrige une incohérence de casse de paramètre qui était discrètement présente dans la procédure stockée GET-by-ID, et discute du moment où renvoyer un 404 versus un 204 pour un enregistrement manquant. L'épisode prévisualise également le passage à l'interface utilisateur, qui devient l'objectif de la prochaine phase de la série C# sur Linux. Si vous avez suivi la série ou êtes en train de câbler DELETE sur une API minimale pour la première fois, cet article explique le point de terminaison complet et la petite refactorisation qui a rendu la liaison des paramètres cohérente à travers le projet.

Mapper le point de terminaison DELETE

[1:02 - 2:14] L'enregistrement du point de terminaison suit la même forme que les autres routes, avec deux ajustements. La route inclut un segment {id:int} pour que l'ID soit passé dans l'URL plutôt que dans le corps, et la signature du gestionnaire utilise MapDelete au lieu de MapPost ou MapPut. Il n'y a pas d'enregistrement d'entrée parce que rien d'autre n'est nécessaire au-delà de l'identifiant.

app.MapDelete("/api/tickets/{id:int}",
    async Task<Results<NoContent, ValidationProblem>>
    (ISqlDataAccess sql, int id) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Delete",
        new { Id = id }, "TicketDB");
    return TypedResults.NoContent();
});
app.MapDelete("/api/tickets/{id:int}",
    async Task<Results<NoContent, ValidationProblem>>
    (ISqlDataAccess sql, int id) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Delete",
        new { Id = id }, "TicketDB");
    return TypedResults.NoContent();
});

Le gestionnaire appelle la procédure stockée spTickets_Delete via le wrapper Dapper, en passant un objet anonyme avec l'ID. Retourner TypedResults.NoContent() produit un statut 204, indiquant que l'opération a réussi et qu'il n'y a pas de corps de réponse à renvoyer. La déclaration de type de retour reflète le point de terminaison PUT de l'épisode précédent, puisque les deux opérations ont le même ensemble de résultats possibles du point de vue du framework.

Correction de l'incohérence de la casse des paramètres

[2:14 - 4:32] En câblant l'appel DELETE, Tim remarque une incohérence qu'il a introduit plus tôt dans la série. La procédure stockée spTickets_Delete utilise un paramètre Id en majuscules, ce qui signifie que l'objet anonyme nécessite une affectation explicite Id = id. La procédure spTickets_Update utilise également Id en majuscules. Mais spTickets_Get, la procédure derrière le point de terminaison GET-par-ID, utilise id en minuscules. Cette variante en minuscules permettait au gestionnaire original de passer new { id } sans affectation explicite, ce qui semblait pratique à l'époque, mais a laissé la base de code incohérente.

Plutôt que de perpétuer l'asymétrie, il ouvre SQL Server Management Studio et modifie la procédure GET pour utiliser Id en majuscules :

ALTER PROCEDURE spTickets_Get
    @Id int
AS
BEGIN
    SELECT Id, Title, Description, DateCompleted, Priority, CreatedDate
    FROM dbo.Tickets
    WHERE Id = @Id;
END

Avec la procédure mise à jour, le gestionnaire GET dans Program.cs a maintenant besoin du même mappage explicite que les gestionnaires DELETE et PUT utilisent, changeant de new { id } à new { Id = id }. Le changement est mécanique, mais la logique est importante : une casse de paramètre cohérente à travers les procédures stockées signifie que chaque point de terminaison lie les paramètres de la même manière, ce qui élimine une petite mais réelle source de confusion lors de la lecture de la couche d'accès aux données plus tard. Une convention qui ne tient que dans une des quatre places n'est pas une convention.

Quand retourner 204 contre 404 pour un enregistrement manquant

[4:46 - 5:46] Après que le point de terminaison compile, Tim s'arrête sur une question de conception qui se pose avec chaque implémentation DELETE. Si l'appelant passe un ID qui n'existe pas, que devrait renvoyer l'API ? Deux réponses raisonnables existent.

Retourner 204 NoContent, que l'on ait supprimé une ligne ou non, traite la requête comme idempotente. Du point de vue de l'appelant, la ressource a disparu, ce qui était l'objectif. C'est ce que fait le gestionnaire actuel, et c'est de cette manière que le projet Tiny Ticket sera livré. Le retour de 404 NotFound pour un enregistrement manquant donne plus d'informations à l'appelant mais nécessite que la procédure stockée indique si une ligne a effectivement été supprimée, généralement en renvoyant un nombre de lignes que le gestionnaire peut inspecter avant de décider quelle réponse envoyer.

Pour une API CRUD interne où le front end sait déjà quels IDs existent (car elle vient de charger la liste), 204 est acceptable. Pour une API publique où les appelants peuvent deviner des IDs, 404 empêche l'illusion silencieuse que des données ont été supprimées alors qu'elles n'ont jamais existé. Tim note que retourner un 404 peut divulguer des informations sur les IDs qui existent dans la base de données, bien qu'il souligne que pour une opération de suppression, le risque pratique est faible puisque exercer le point de terminaison implique déjà un accès en écriture.

Test via Swagger

[5:46 - 7:08] Avec la base de données en cours d'exécution, Tim lance l'API et ouvre Swagger. Il commence par GET all pour prendre note des données actuelles : enregistrements 1, 2, 3 de la graine originale, plus 107, 109 et 110 restants des tests d'insertion précédents.

Il exécute DELETE sur 107 et obtient un 204 en retour. Même chose pour 110. Pour vérifier le comportement d'enregistrement manquant, il exécute DELETE sur 1011, un ID qui n'a jamais été dans la base de données. La réponse est toujours un 204, sans indication que rien n'a été supprimé. C'est le compromis discuté dans la section précédente, maintenant visible dans la réponse actuelle de l'API.

Un deuxième GET all confirme l'état final: les enregistrements 1, 2, 3, et 109 restent. Le point de terminaison DELETE fonctionne pour les IDs valides et échoue silencieusement pour ceux qui sont invalides, exactement comme l'implémentation le spécifie.

Clôture : CRUD complet

[7:08 - 8:38] L'ajout de DELETE complète les quatre verbes CRUD pour l'API Tiny Ticket. Le même modèle structurel se retrouve dans chaque point de terminaison : définition de la route, nom de la procédure stockée, appel d'accès aux données Dapper, résultat typé. Tim est franc qu'une API de production ajouterait probablement plus de points de terminaison, tels qu'un PATCH pour marquer un ticket comme terminé sans envoyer tout l'objet à travers le tuyau, ou un point de terminaison de recherche dédié. Le but de la série, cependant, est de garder chaque couche concentrée afin que la couche suivante (le front end) ait une surface propre sur laquelle appeler.

La cohérence est ce qui rend le projet agréable à lire. Le wrapper Dapper, le modèle d'insertion POST, le pipeline de validation et les résultats typés se combinent pour que chaque nouveau point d'extrémité prenne à peu près la même quantité de code, quel que soit le verbe qu'il implémente. Cette prévisibilité est ce qui fait de l'API un objectif agréable pour le travail front-end qui suit.

Conclusion

[8:38 - 8:40] L'ajout d'un point de terminaison DELETE à une API minimale nécessite un enregistrement MapDelete avec un segment ID dans la route, un appel de procédure stockée via le wrapper d'accès aux données, et un retour TypedResults.NoContent(). Le point d'extrémité complète la surface CRUD du projet Tiny Ticket et prépare le passage au front-end dans la prochaine phase de la série.

Navigation de la série : Cet article fait partie de la série C# sur Linux qui construit l'application Tiny Ticket. Précédent : Ajouter un point d'extrémité de mise à jour PUT. Phase suivante : pages front-end qui consomment l'API.

Astuce Exemple : Si vous souhaitez une réponse DELETE plus informative sans changer la procédure stockée, capturez le compte de lignes affectées de SaveDataAsync et renvoyez un TypedResults.NotFound() lorsque le compte est zéro. Cela ajoute le chemin 404 sans restructurer la couche d'accès aux données.

Regardez la vidéo complète sur sa chaîne YouTube et obtenez plus d'informations sur la construction de points d'extrémité CRUD dans la série C# sur Linux.

Hero Worlddot related to Ajout d'un point de terminaison DELETE dans .NET Aspire sur Linux
Hero Affiliate related to Ajout d'un point de terminaison DELETE dans .NET Aspire sur Linux

Gagnez plus en partageant ce que vous aimez

Vous créez du contenu pour les développeurs travaillant avec .NET, C#, Java, Python ou Node.js ? Transformez votre expertise en revenu supplémentaire !

Équipe de soutien Iron

Nous sommes en ligne 24 heures sur 24, 5 jours sur 7.
Chat
Email
Appelez-moi