Pourquoi API REST avec .NET ?
L'API REST (Representational State Transfer) est une architecture web qui permet de créer des services Web basés sur les protocoles HTTP. Elle est particulièrement populaire pour les applications modernes en raison de sa simplicité, de sa flexibilité et de son large support.
Un cas d'utilisation concret serait le développement d'un site e-commerce : chaque produit pourrait être une ressource RESTful, avec des méthodes GET pour récupérer les détails du produit, POST pour ajouter un nouveau produit, PUT pour mettre à jour un produit existant et DELETE pour le supprimer.
Prerequis
- Connaissance de base de C# et .NET Core
- Visual Studio 2019 ou ultérieure
- .NET SDK 5.0 ou ultérieure
- Git (pour cloner le projet fil rouge)
Concepts fondamentaux
Ressources et Endpoints
Dans une API REST, chaque ressource est identifiée par un URI (Uniform Resource Identifier). Les endpoints sont les points d'entrée de l'API qui permettent de manipuler ces ressources.
// Exemple de ressource : un utilisateur
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
// Endpoint pour récupérer tous les utilisateurs
app.MapGet("/users", () => users);
Méthodes HTTP
Les méthodes HTTP définissent l'action à effectuer sur une ressource.
- GET : Récupère les données d'une ressource.
- POST : Crée une nouvelle ressource.
- PUT : Met à jour une ressource existante.
- DELETE : Supprime une ressource.
app.MapPost("/users", (User user) =>
{
users.Add(user);
return Results.Created($"/users/{user.Id}", user);
});
app.MapPut("/users/{id}", (int id, User user) =>
{
var existingUser = users.FirstOrDefault(u => u.Id == id);
if (existingUser != null)
{
existingUser.Name = user.Name;
existingUser.Email = user.Email;
return Results.NoContent();
}
return Results.NotFound();
});
app.MapDelete("/users/{id}", (int id) =>
{
var userToRemove = users.FirstOrDefault(u => u.Id == id);
if (userToRemove != null)
{
users.Remove(userToRemove);
return Results.Ok();
}
return Results.NotFound();
});
Sérialisation et Deserialisation
La sérialisation consiste à convertir les objets en format JSON ou XML, tandis que la deserialisation est le processus inverse.
// Sérialisation d'un objet User en JSON
var userJson = JsonSerializer.Serialize(user);
// Deserialisation du JSON en un objet User
var newUser = JsonSerializer.Deserialize<User>(userJson);
Mise en pratique : projet fil rouge
Étape 1 : Création du projet
dotnet new webapi -n TaskManagerApi
cd TaskManagerApi
Étape 2 : Ajout des modèles et du service de tâches
Créez un fichier Models/Task.cs :
public class Task
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsCompleted { get; set; }
}
Ajoutez une liste de tâches dans le fichier Program.cs :
var tasks = new List<Task>
{
new Task { Id = 1, Title = "Tâche 1", IsCompleted = false },
new Task { Id = 2, Title = "Tâche 2", IsCompleted = true }
};
Étape 3 : Création des endpoints
Ajoutez les endpoints dans le fichier Program.cs :
app.MapGet("/tasks", () => tasks);
app.MapPost("/tasks", (Task task) =>
{
task.Id = tasks.Max(t => t.Id) + 1;
tasks.Add(task);
return Results.Created($"/tasks/{task.Id}", task);
});
app.MapPut("/tasks/{id}", (int id, Task updatedTask) =>
{
var task = tasks.FirstOrDefault(t => t.Id == id);
if (task != null)
{
task.Title = updatedTask.Title;
task.IsCompleted = updatedTask.IsCompleted;
return Results.NoContent();
}
return Results.NotFound();
});
app.MapDelete("/tasks/{id}", (int id) =>
{
var task = tasks.FirstOrDefault(t => t.Id == id);
if (task != null)
{
tasks.Remove(task);
return Results.Ok();
}
return Results.NotFound();
});
Étape 4 : Test des endpoints
Lancez l'application :
dotnet run
Accédez à http://localhost:5000/tasks pour voir les tâches et utiliser les autres endpoints.
Erreurs frequentes et debugging
Erreur: Les tâches ne sont pas ajoutées correctement.
// Code incorrect app.MapPost("/tasks", (Task task) => { tasks.Add(task); return Results.Created($"/tasks/{task.Id}", task); });Correction:
// Code correct app.MapPost("/tasks", (Task task) => { task.Id = tasks.Max(t => t.Id) + 1; tasks.Add(task); return Results.Created($"/tasks/{task.Id}", task); });Erreur: L'API retourne une erreur 404 pour les requêtes PUT et DELETE.
// Code incorrect app.MapPut("/tasks/{id}", (int id, Task updatedTask) => { var task = tasks.FirstOrDefault(t => t.Id == id); if (task != null) { task.Title = updatedTask.Title; task.IsCompleted = updatedTask.IsCompleted; return Results.NoContent(); } return Results.NotFound(); });Correction:
// Code correct app.MapPut("/tasks/{id}", (int id, Task updatedTask) => { var task = tasks.FirstOrDefault(t => t.Id == id); if (task != null) { task.Title = updatedTask.Title; task.IsCompleted = updatedTask.IsCompleted; return Results.NoContent(); } return Results.NotFound(); }); app.MapDelete("/tasks/{id}", (int id) => { var task = tasks.FirstOrDefault(t => t.Id == id); if (task != null) { tasks.Remove(task); return Results.Ok(); } return Results.NotFound(); });
Pour aller plus loin
- Authentification et autorisation : Utilisez le middleware JWT pour protéger les endpoints.
- Pagination et filtrage : Ajoutez des paramètres de pagination et de filtrage aux endpoints GET.
- Validation des données : Utilisez la validation DataAnnotations pour s'assurer que les données entrées sont valides.
Défi pratique : Ajouter une fonctionnalité permettant d'ajouter des commentaires à chaque tâche, et créer les endpoints associés.