Skip to content
Learni
Voir tous les tutoriels
Développement Backend

Comment créer une API REST avec ASP.NET Core en 2026

Read in English

Introduction

ASP.NET Core est le framework open-source de Microsoft pour développer des applications web modernes, scalables et performantes. En 2026, il reste le choix n°1 pour les APIs REST en entreprise grâce à sa vitesse, sa compatibilité cross-platform (Windows, Linux, macOS) et son intégration native avec C# 13+.

Ce tutoriel beginner vous guide pas à pas pour créer une API REST complète gérant des produits : endpoints CRUD, validation, Swagger pour les tests et logging. Pourquoi c'est crucial ? Les APIs alimentent 90% des apps modernes (microservices, mobile, frontend SPA). Sans bases solides, vous risquez des failles de sécurité ou des perfs médiocres.

On part des fondations (.NET 10 SDK) vers du code production-ready. À la fin, vous aurez un projet copier-collable, déployable sur Azure ou Docker. Temps estimé : 30 min. Analogy : comme assembler un moteur Lego, chaque bloc s'emboîte parfaitement pour un résultat fluide.

Prérequis

  • .NET 10 SDK installé (téléchargez sur dotnet.microsoft.com)
  • Éditeur de code : Visual Studio 2022+ ou VS Code avec extension C#
  • Connaissances de base en HTTP/REST et C# (variables, classes)
  • Terminal (PowerShell, Bash ou CMD)
  • 5 min pour vérifier : dotnet --version doit afficher 10.x.x

Créer et lancer le projet de base

terminal
dotnet new webapi -o MonApiProduit --no-https
cd MonApiProduit
dotnet restore
dotnet run

Cette commande crée un projet Web API minimal avec un contrôleur WeatherForecast par défaut, restaure les packages NuGet et lance le serveur sur https://localhost:5xxx ou http://localhost:5xxx. Le flag --no-https évite les certs auto-signés pour débuter. Vérifiez l'API à http://localhost:5xxx/swagger.

Comprendre la structure du projet

Votre projet contient :

  • Program.cs : Point d'entrée unique (depuis .NET 6), configure services et middleware.
  • Controllers/ : Dossier pour les contrôleurs REST.
  • appsettings.json : Config (ports, logging).
  • Swagger est pré-inclus pour tester les endpoints graphiquement.

Analogie : Program.cs est le chef d'orchestre, les contrôleurs les solistes. Supprimez le contrôleur WeatherForecast pour repartir propre.

Configurer Program.cs pour Swagger et CORS

Program.cs
var builder = WebApplication.CreateBuilder(args);

// Ajout services
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// CORS pour frontend
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll", policy =>
    {
        policy.AllowAnyOrigin()
              .AllowAnyMethod()
              .AllowAnyHeader();
    });
});

var app = builder.Build();

// Pipeline middleware
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseCors("AllowAll");
app.UseAuthorization();
app.MapControllers();

app.Run();

Ce code configure l'API avec contrôleurs, Swagger (UI auto à /swagger) et CORS pour autoriser les appels depuis n'importe quel origin (idéal dev). Le pipeline middleware s'exécute séquentiellement : dev-only Swagger, puis CORS avant routing. Piège : Oublier CORS bloque les fetch frontend.

Créer le modèle Produit

Models/Produit.cs
namespace MonApiProduit.Models;

public class Produit
{
    public int Id { get; set; }
    public string? Nom { get; set; }
    public decimal Prix { get; set; }
    public string? Description { get; set; }
    public DateTime DateCreation { get; set; } = DateTime.UtcNow;
}

public class CreateProduitDto
{
    public string Nom { get; set; } = string.Empty;
    public decimal Prix { get; set; }
    public string? Description { get; set; }
}

Définit un modèle Produit pour la DB (futur EF Core) et un DTO pour les POST (évite overposting). DateCreation auto pour audit. DTO protège contre injections en n'exposant pas Id. Piège : Sans DTO, un attaquant peut setter Id et bypass la logique d'auto-incrément.

Ajouter un service en mémoire (repo simulé)

Pour simuler une DB sans EF Core (beginner-friendly), créez un repository en mémoire. C'est un Singleton list avec méthodes CRUD thread-safe. Analogy : Comme un Excel partagé, mais locké pour multi-accès.

Implémenter le repository Produit

Services/IProduitRepository.cs
using MonApiProduit.Models;

namespace MonApiProduit.Services;

public interface IProduitRepository
{
    IEnumerable<Produit> GetAll();
    Produit? GetById(int id);
    void Create(Produit produit);
    void Update(int id, Produit produit);
    void Delete(int id);
}

Interface pour dependency injection (DI testable). Sépare logique métier de contrôleurs. En prod, implémentez avec EF Core/SQLite.

Implémentation du repository en mémoire

Services/ProduitRepository.cs
using MonApiProduit.Models;

namespace MonApiProduit.Services;

public class ProduitRepository : IProduitRepository
{
    private static readonly List<Produit> _produits = new();
    private static int _nextId = 1;

    public IEnumerable<Produit> GetAll() => _produits;

    public Produit? GetById(int id) => _produits.FirstOrDefault(p => p.Id == id);

    public void Create(Produit produit)
    {
        produit.Id = Interlocked.Increment(ref _nextId);
        _produits.Add(produit);
    }

    public void Update(int id, Produit produit)
    {
        var existing = GetById(id);
        if (existing != null)
        {
            existing.Nom = produit.Nom;
            existing.Prix = produit.Prix;
            existing.Description = produit.Description;
        }
    }

    public void Delete(int id)
    {
        var produit = GetById(id);
        if (produit != null)
            _produits.Remove(produit);
    }
}

Repo mock avec List thread-safe (Interlocked pour Id). FirstOrDefault gère l'absence. Update/Delete null-safe. Piège : Sans Interlocked, race conditions en multi-thread (IIS/Kestrel).

Enregistrer le service en DI

Program.cs (ajout)
// Dans builder.Services, avant var app =
using MonApiProduit.Services;

builder.Services.AddSingleton<IProduitRepository, ProduitRepository>();

Ajoutez ceci avant builder.Build(). Singleton pour état partagé (comme DB). Scoped en prod pour EF. DI auto-injecte en contrôleurs.

Créer le contrôleur ProduitsController

Controllers/ProduitsController.cs
using Microsoft.AspNetCore.Mvc;
using MonApiProduit.Models;
using MonApiProduit.Services;

namespace MonApiProduit.Controllers;

[ApiController]
[Route("api/[controller]")]
public class ProduitsController : ControllerBase
{
    private readonly IProduitRepository _repository;

    public ProduitsController(IProduitRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    public ActionResult<IEnumerable<Produit>> GetAll()
    {
        return Ok(_repository.GetAll());
    }

    [HttpGet("{id}")]
    public ActionResult<Produit> GetById(int id)
    {
        var produit = _repository.GetById(id);
        if (produit == null)
            return NotFound();
        return Ok(produit);
    }

    [HttpPost]
    public ActionResult<Produit> Create([FromBody] CreateProduitDto dto)
    {
        var produit = new Produit
        {
            Nom = dto.Nom,
            Prix = dto.Prix,
            Description = dto.Description
        };
        _repository.Create(produit);
        return CreatedAtAction(nameof(GetById), new { id = produit.Id }, produit);
    }

    [HttpPut("{id}")]
    public IActionResult Update(int id, [FromBody] CreateProduitDto dto)
    {
        var produit = _repository.GetById(id);
        if (produit == null)
            return NotFound();
        _repository.Update(id, new Produit
        {
            Id = id,
            Nom = dto.Nom,
            Prix = dto.Prix,
            Description = dto.Description
        });
        return NoContent();
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
        var produit = _repository.GetById(id);
        if (produit == null)
            return NotFound();
        _repository.Delete(id);
        return NoContent();
    }
}

Contrôleur RESTful complet (CRUD) avec [ApiController] pour validation auto et binding. Constructor injection DI. Status codes HTTP standards (201 Created, 204 NoContent). Piège : Sans CreatedAtAction, HATEOAS brisé pour clients.

Tester l'API avec Swagger

Relancez dotnet run. Ouvrez http://localhost:5xxx/swagger :

  • GET /api/Produits : Liste vide.
  • POST : {"nom":"Laptop","prix":999.99,"description":"Gaming"} → Notez l'Id.
  • GET /api/Produits/1, PUT, DELETE.

Swagger génère docs auto. Ajoutez ? pour query params futurs.

Bonnes pratiques

  • Toujours utiliser DTOs : Sépare input/output, évite overposting/sec leaks.
  • Validation : Ajoutez [Required] sur DTO + app.UseModelValidation() (auto avec ApiController).
  • Logging : Injectez ILogger, loggez erreurs/exceptions.
  • Async : Passez tout en Task (await _repo.GetAllAsync()) pour scalabilité.
  • Rate limiting : Ajoutez builder.Services.AddRateLimiter() en 2026 pour DDoS protection.

Erreurs courantes à éviter

  • Port occupé : Changez "Urls": "http://localhost:5000" dans launchSettings.json.
  • CORS bloqué : Vérifiez ordre middleware (CORS avant UseAuthorization).
  • NullReference : Toujours null-check avant Update/Delete.
  • HTTPS forcé : En dev, --no-https ; prod, certs Let's Encrypt.

Pour aller plus loin

Passez à EF Core pour DB réelle : dotnet ef migrations add Initial. Auth JWT avec Identity. Déployez sur Azure App Service.

Découvrez nos formations Learni sur ASP.NET Core pour masterclass avancées (signalR, Blazor, gRPC).