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 POST Insert avec validation dans .NET Aspire sur Linux

[[academy-video-youtube({"vid": "oAMMHR8kKnw", "start_time": "0", "title": "Ajout d'un point de terminaison POST avec validation dans .NET Aspire sur Linux", "creator": "Tim Corey", "length": "20m 31s"})]]

Lire des données d'une API n'est que la moitié de l'histoire. Finalement, chaque application doit accepter de nouveaux enregistrements, ce qui signifie créer un point d'extrémité POST qui reçoit un corps de requête, valide l'entrée, la persiste dans la base de données, et retourne un code de statut significatif. Sauter l'étape de validation est tentant lors du prototypage, mais les API de production qui acceptent des entrées non validées deviennent une source de données corrompues plus difficile à nettoyer qu'à prévenir.

Dans sa vidéo "Adding a POST Insert Endpoint with Validation in .NET Aspire on Linux", Tim Corey ajoute un point d'insertion à la Tiny Ticket API, crée un type d'enregistrement d'entrée dédié, connecte le pipeline de validation intégré de .NET pour les API minimales, et configure Swagger pour se lancer automatiquement au démarrage de l'API. L'épisode couvre le cycle complet de la procédure stockée au point d'extrémité testé, y compris le format de réponse d'erreur de validation que .NET retourne par défaut. Si vous suivez la série C# sur Linux ou ajoutez les opérations d'écriture à une API minimale pour la première fois, cet article vous guide à travers chaque étape.

Création du type d'enregistrement d'insertion

[1:46 - 4:43] Avant de construire le point de terminaison, Tim crée un objet de transfert de données qui représente la forme d'une requête d'insertion. L'existant TicketModel inclut des champs comme Id et CreatedDate que la base de données génère automatiquement. Les accepter dans un corps POST seraient soit ignorés, soit causeraient des conflits, donc un type séparé limite l'entrée uniquement aux champs que l'appelant doit fournir.

public record TicketInsertRecord(string Title, string Description, int Priority);
public record TicketInsertRecord(string Title, string Description, int Priority);

Utiliser un record au lieu d'un class est un choix délibéré. Les enregistrements fournissent l'égalité basée sur la valeur et l'immutabilité par défaut, ce qui correspond à la sémantique d'une charge utile de requête : les données arrivent, sont validées, sont transmises à la base de données, et ne sont jamais modifiées entre-temps. Les trois propriétés (Titre, Description, Priorité) correspondent directement aux paramètres de la procédure stockée spTickets_Insert.

Mapping du point d'extrémité POST

[4:43 - 9:51] Avec le type d'enregistrement défini, l'enregistrement du point de terminaison suit le même modèle que les routes GET, mais utilise MapPost et lie le corps de la requête à l'enregistrement d'insertion :

app.MapPost("/api/tickets", async (TicketInsertRecord ticket, IDbConnection db) =>
{
    await db.SaveDataAsync("spTickets_Insert", ticket);
    return Results.NoContent();
});
app.MapPost("/api/tickets", async (TicketInsertRecord ticket, IDbConnection db) =>
{
    await db.SaveDataAsync("spTickets_Insert", ticket);
    return Results.NoContent();
});

Notez que la route est /api/tickets sans segment ID, conformément aux conventions REST où POST vers une URL de collection crée une nouvelle ressource. Le gestionnaire appelle la procédure stockée avec l'objet entier ticket comme sac de paramètres. Dapper mappe les propriétés de l'enregistrement aux paramètres SQL par nom.

Retourner Results.NoContent() envoie un code statut 204. Tim explique la raison : l'insertion a réussi, mais il n'y a rien de significatif à retourner dans le corps de la réponse. Certaines APIs renvoient l'objet nouvellement créé avec un statut 201 Créé et un en-tête Location pointant vers la nouvelle ressource, ce qui est une alternative valide. Pour le projet Tiny Ticket, 204 garde les choses légères.

Tester l'insertion via Swagger

[9:51 - 14:43] Tim launches the project and navigates to Swagger. Le point de terminaison POST apparaît avec un schéma de corps de requête correspondant aux propriétés TicketInsertRecord. Il remplit un billet test avec un titre, une description, et une priorité, puis exécute la requête.

Un 204 revient, confirmant que l'insertion a réussi. Pour vérifier que les données ont bien persisté, il bascule sur le point d'extrémité GET all et l'exécute. Le nouveau billet apparaît dans la liste à côté des enregistrements de test d'origine.

Ce que le test révèle également, c'est l'écart sans validation : envoyer un titre vide, une description manquante ou une priorité de 99 réussissent tous avec un 204. La base de données accepte tout ce que l'API envoie. Cet écart motive la section suivante.

Ajouter une validation intégrée

[14:43 - 18:28] À partir de .NET 10, les API minimales prennent en charge un pipeline de validation intégré qui lit les attributs d'annotation de données du type d'entrée et rejette les requêtes non valides avant que le gestionnaire ne s'exécute. Tim le connecte en deux étapes.

Tout d'abord, enregistrez les services de validation dans Program.cs. Cette ligne unique active tout le pipeline :

builder.Services.AddValidation();
builder.Services.AddValidation();

Avec le service enregistré, le framework inspecte chaque corps de requête pour les attributs de validation avant que le gestionnaire ne s'exécute. La deuxième étape consiste à annoter l'enregistrement d'insertion avec les règles que chaque champ doit respecter :

public record TicketInsertRecord(
    [Required, MinLength(1)] string Title,
    [Required] string Description,
    [Range(1, 5)] int Priority
);
public record TicketInsertRecord(
    [Required, MinLength(1)] string Title,
    [Required] string Description,
    [Range(1, 5)] int Priority
);

[Required] assure que le champ est présent et non nul. [MinLength(1)] empêche les chaînes vides de passer la vérification requise (puisqu'une chaîne vide n'est techniquement pas nulle). [Range(1, 5)] limite la priorité à un niveau valide. Ces attributs sont des types System.ComponentModel.DataAnnotations que les contrôleurs ASP.NET MVC ont utilisés pendant des années, mais ils fonctionnent maintenant dans les APIs minimales sans middleware supplémentaire.

Après avoir sauvegardé et redémarré, Tim envoie une requête avec un titre vide et une priorité de 10. La réponse revient en tant que 400 Bad Request avec un corps d'erreur structuré :

{
    "errors": {
        "Title": ["The Title field is required."],
        "Priority": ["The field Priority must be between 1 and 5."]
    }
}

Le pipeline de validation court-circuite la requête avant que le gestionnaire ne s'exécute, donc aucune donnée non valide n'atteint la base de données. La réponse d'erreur suit le format RFC 7807 Problem Details, que les consommateurs d'API peuvent analyser automatiquement.

Lancement automatique de Swagger au démarrage

[19:44 - 20:31] Une petite amélioration de la qualité de vie clôt l'épisode. Chaque fois que Tim lançait l'API, il devait taper manuellement /swagger dans l'URL du navigateur. Pour automatiser cela, il ouvre Properties/launchSettings.json du projet d'API et ajoute une propriété launchUrl au profil HTTPS :

{
    "profiles": {
        "https": {
            "launchUrl": "swagger"
        }
    }
}

Au prochain lancement, le navigateur s'ouvre directement sur le Swagger UI au lieu de la page par défaut. Cela économise quelques secondes par cycle de débogage, ce qui se cumule sur une session de développement complète.

Conclusion

[20:09 - 20:31] Ajouter un point de terminaison POST à une API minimale implique de créer un enregistrement d'entrée dédié, de le mapper à MapPost avec l'URL de la collection, et d'appeler la procédure stockée avec l'enregistrement comme objet paramètre. La validation dans .NET 10 nécessite une inscription de service et des attributs d'annotation de données standard sur les propriétés de l'enregistrement. Le framework traite automatiquement le formatage de la réponse 400.

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é Get By ID. Prochain : Ajouter un point d'extrémité de mise à jour PUT.

Conseil Exemple : Lorsque votre procédure stockée d'insertion renvoie l'ID du nouvel enregistrement, changez le retour de Results.NoContent() à Results.Created($"/api/tickets/{newId}", result) pour donner aux appelants un statut 201 avec un en-tête de localisation qu'ils peuvent suivre pour récupérer la ressource créée.

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

Hero Worlddot related to Ajout d'un point de terminaison POST Insert avec validation dans .NET Aspire sur Linux
Hero Affiliate related to Ajout d'un point de terminaison POST Insert avec validation 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