.NET  

Everything You Need to Know About Minimal APIs in .NET

Minimal APIs are a lightweight way to build HTTP APIs in .NET with minimal ceremony. Introduced in .NET 6, they focus on simplicity and performance.

Minimal APIs eliminate the complexity of traditional ASP.NET Core MVC. No controllers, no heavy configuration.

Why Choose Minimal APIs?

  • Efficiency: Achieve more with less code.
  • High Performance: Lightweight and optimized for fast execution.
  • Beginner-Friendly: Minimal APIs are easy to learn and implement, especially for those new to .NET.
  • Flexible & Scalable: Don't be fooled by the name, Minimal APIs can power everything from microservices to enterprise-grade systems.

Build a Minimal API Project from Scratch

Let's walk through creating a Minimal API using the .NET CLI or Visual Studio.

Step 1. Create the Project

dotnet new web -n MinimalApiDemo
cd MinimalApiDemo
start MinimalApiDemo.sln

Step 2. Add Your First Endpoint

A typical start can always, a hello world project.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello from Minimal API!");
app.Run();

Run the app

dotnet run

Navigate to https://localhost:5001/ and you'll see the response.

"Hello from Minimal API!"

Step 3. Adding models and services

Now, let's go ahead and make our project more like a real project, starting by.

Create the Product model Models/Product.cs.

namespace ProductApi.Models
{
    public class Product
    {
        public Guid Id { get; set; } = Guid.NewGuid();
        public string Name { get; set; } = string.Empty;
        public decimal Price { get; set; }
    }
}

Create a file: Services/IProductService.cs.

using ProductApi.Models;

namespace ProductApi.Services
{
    public interface IProductService
    {
        IEnumerable<Product> GetAll();
        Product? GetById(Guid id);
        Product Create(Product product);
        bool Delete(Guid id);
        Product? Update(Guid id, Product updatedProduct);
    }
}

Now create the implementation in Services/ProductService.cs.

using ProductApi.Models;

namespace ProductApi.Services
{
    public class ProductService : IProductService
    {
        private readonly List<Product> _products = new();

        public IEnumerable<Product> GetAll() => _products;

        public Product? GetById(Guid id) =>
            _products.FirstOrDefault(p => p.Id == id);

        public Product Create(Product product)
        {
            _products.Add(product);
            return product;
        }

        public bool Delete(Guid id)
        {
            var product = GetById(id);
            if (product == null) return false;

            _products.Remove(product);
            return true;
        }

        public Product? Update(Guid id, Product updatedProduct)
        {
            var product = GetById(id);
            if (product == null) return null;

            product.Name = updatedProduct.Name;
            product.Price = updatedProduct.Price;
            return product;
        }
    }
}

This project is too simple just to demonstrate the usage of minimal APIs, thus no databaseis configured.

Update your Program and register the service.

using ProductApi.Models;
using ProductApi.Services;

var builder = WebApplication.CreateBuilder(args);

// Add Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Register services
builder.Services.AddSingleton<IProductService, ProductService>();

var app = builder.Build();

// Swagger middleware
app.UseSwagger();
app.UseSwaggerUI();

// Routes
app.MapGet("/", () => "Product Minimal API Example");

app.MapGet("/products", (IProductService service) =>
{
    return Results.Ok(service.GetAll());
});

app.MapGet("/products/{id}", (Guid id, IProductService service) =>
{
    var product = service.GetById(id);
    return product is null ? Results.NotFound() : Results.Ok(product);
});

app.MapPost("/products", (Product product, IProductService service) =>
{
    var created = service.Create(product);
    return Results.Created($"/products/{created.Id}", created);
});

app.MapPut("/products/{id}", (Guid id, Product updated, IProductService service) =>
{
    var product = service.Update(id, updated);
    return product is null ? Results.NotFound() : Results.Ok(product);
});

app.MapDelete("/products/{id}", (Guid id, IProductService service) =>
{
    return service.Delete(id) ? Results.NoContent() : Results.NotFound();
});

app.Run();

Run the app

dotnet run

Now open your browser and go to: http://localhost:5000/swagger.

You'll see a full Swagger UI with your Minimal API CRUD for Product.

Now seeing that the example is simple, showing how we create a minimal API, a question may be asked here *How do Minimal APIs fit into a more complex, real-world architecture like DDD or Clean Architecture?

Great question, and yes, Minimal APIs can scale into complex, maintainable solutions. The trick is separating responsibilities properly and treating Minimal APIs purely as the transport layer, not the place for business logic.

Example: Clean Architecture + Minimal APIs

Here's a quick breakdown of how you could structure a real application using Clean Architecture with Minimal APIs.

/ProductApi
│── Program.cs
│── Endpoints (Minimal API endpoints)
│   └── ProductsEndpoint.cs
│── Application (Services / DTOs)
│   └── Interfaces
│   └── Services
│── Domain (Domain models, enums)
│   └── Entities
│── Infrastructure (DB context, repositories, external APIs)

Key Takeaways

  • Minimal APIs are not just for simple apps; they're flexible enough for complex architectures.
  • The key is to apply SOLID principles, layer separation, and dependency injection wisely.

Improved in .NET 7 and .NET 87

With newer versions of .NET, minimal APIs now support.

  • Request validation
  • OpenAPI/Swagger generation
  • Dependency injection
  • Route groups and filters
  • Authorization policies