SyntaxStudy
Sign Up
C# ASP.NET Core Minimal APIs
C# Beginner 1 min read

ASP.NET Core Minimal APIs

ASP.NET Core Minimal APIs (introduced in .NET 6, refined in .NET 7 and 8) allow you to build HTTP APIs with far less ceremony than the traditional controller-based MVC approach. Routes are defined inline with `app.MapGet`, `app.MapPost`, etc., and handler delegates can return plain objects, `IResult` values, or typed `Results` for OpenAPI documentation. Dependency injection is fully supported in minimal API handlers: declare constructor parameters or add parameters to the handler delegate and the DI container resolves them automatically. Services are registered in `builder.Services` before `builder.Build()` is called. .NET 8 introduces route groups (`app.MapGroup`) to organise related endpoints under a common prefix and apply shared middleware or filters. This keeps larger APIs structured without moving to controllers. OpenAPI/Swagger documentation is generated automatically from the route metadata and can be served via `app.MapOpenApi()`.
Example
// Minimal API — full example with DI, route groups, and OpenAPI

using Microsoft.AspNetCore.Http.HttpResults;

var builder = WebApplication.CreateBuilder(args);

// Register services
builder.Services.AddSingleton<IProductRepository, InMemoryProductRepository>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();

// Route group — all routes share /api/products prefix
var products = app.MapGroup("/api/products").WithOpenApi();

products.MapGet("/", (IProductRepository repo) =>
    Results.Ok(repo.GetAll()));

products.MapGet("/{id:int}", (int id, IProductRepository repo) =>
    repo.GetById(id) is { } p
        ? Results.Ok(p)
        : Results.NotFound(new { Message = $"Product {id} not found" }));

products.MapPost("/", (Product product, IProductRepository repo) =>
{
    repo.Add(product);
    return Results.Created($"/api/products/{product.Id}", product);
});

products.MapDelete("/{id:int}", (int id, IProductRepository repo) =>
    repo.Remove(id) ? Results.NoContent() : Results.NotFound());

app.Run();

// ----- Models and in-memory repository -----
record Product(int Id, string Name, decimal Price);

interface IProductRepository
{
    IEnumerable<Product> GetAll();
    Product? GetById(int id);
    void Add(Product p);
    bool Remove(int id);
}

class InMemoryProductRepository : IProductRepository
{
    private readonly List<Product> _items = new()
    {
        new(1, "Laptop",   999.99m),
        new(2, "Keyboard",  79.99m),
    };
    public IEnumerable<Product> GetAll()    => _items;
    public Product? GetById(int id)          => _items.FirstOrDefault(p => p.Id == id);
    public void Add(Product p)               => _items.Add(p);
    public bool Remove(int id)
    {
        var p = GetById(id);
        return p is not null && _items.Remove(p);
    }
}