Skip to content

Aspnet Minimal Api

DodaTech 4 min read

title: ASP.NET Core Minimal API — Complete Guide to Lightweight Endpoints description: 'Learn ASP.NET Core Minimal APIs: creating lightweight endpoints, parameter binding, dependency injection, validation, OpenAPI docs, and when to use Minimal over MVC.' date: 2026-06-28 lastmod: 2026-06-28 weight: 27 tags: [backend, aspnet]


ASP.NET Core Minimal APIs provide a simplified approach to building HTTP APIs with minimal boilerplate, perfect for microservices, small services, and simple endpoints.

## What You'll Learn

By the end of this tutorial, you'll create Minimal API endpoints, handle parameters and binding, use dependency injection, add validation, document with OpenAPI, and choose between Minimal and MVC.

## Real-World Use

A microservice that sends emails has 3 endpoints: POST /send, GET /status/{id}, GET /health. Minimal API requires only 20 lines of code versus 50+ with controllers.

## Minimal API Learning Path

```mermaid
flowchart LR
  A[Web API] --> B[Minimal API]
  B --> C[SignalR]
  C --> D[Testing]
  D --> E[Logging]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Basic Endpoints

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");
app.MapGet("/api/time", () => Results.Ok(new { Time = DateTime.UtcNow }));
app.MapGet("/api/status", () => Results.Ok(new { Status = "Healthy", Uptime = Environment.TickCount64 }));

app.Run();

Parameter Binding

// Route parameters
app.MapGet("/api/users/{id:int}", (int id) =>
    Results.Ok(new { UserId = id }));

// Query parameters
app.MapGet("/api/products", (string? category, [FromQuery] int page = 1) =>
    Results.Ok(new { Category = category, Page = page }));

// Body binding
app.MapPost("/api/products", (CreateProductDto product) =>
    Results.Created($"/api/products/{product.Name}", product));

// Form binding
app.MapPost("/api/upload", (IFormFile file) =>
    Results.Ok(new { FileName = file.FileName, Size = file.Length }));

Dependency Injection

// Register services
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddDbContext<AppDbContext>(o => o.UseSqlServer(connStr));
builder.Services.AddSingleton<ICache, MemoryCache>();

// Inject into endpoints
app.MapGet("/api/products", async (IProductService service) =>
    Results.Ok(await service.GetAllAsync()));

app.MapGet("/api/products/{id}", async (int id, AppDbContext db) =>
{
    var product = await db.Products.FindAsync(id);
    return product is null ? Results.NotFound() : Results.Ok(product);
});

Validation with Filters

// Endpoint filter for validation
app.MapPost("/api/products", async (CreateProductDto product, AppDbContext db) =>
{
    var product = await db.Products.AddAsync(new Product { Name = product.Name, Price = product.Price });
    await db.SaveChangesAsync();
    return Results.Created($"/api/products/{product.Entity.Id}", product.Entity);
}).AddEndpointFilter(async (context, next) =>
{
    var product = context.Arguments.OfType<CreateProductDto>().FirstOrDefault();
    if (product is null || string.IsNullOrWhiteSpace(product.Name))
        return Results.BadRequest("Product name is required");
    return await next(context);
});

Grouping Endpoints

var products = app.MapGroup("/api/products")
    .WithTags("Products")
    .RequireAuthorization();

products.MapGet("/", async (IProductService s) => Results.Ok(await s.GetAllAsync()));
products.MapGet("/{id:int}", async (int id, IProductService s) =>
{
    var p = await s.GetByIdAsync(id);
    return p is null ? Results.NotFound() : Results.Ok(p);
});
products.MapPost("/", async (CreateProductDto dto, IProductService s) =>
{
    var p = await s.CreateAsync(dto);
    return Results.Created($"/api/products/{p.Id}", p);
});

Common Mistakes

1. Too Complex for Minimal API

Minimal APIs shine for simple endpoints. Complex request handling belongs in controllers.

2. Missing OpenAPI Description

Without .WithName() and .WithOpenApi(), Swagger shows generic operation IDs.

3. Not Using Result Types

Returning raw objects loses status code control (always returns 200). Use Results.Ok(), Results.NotFound(), Results.Created().

4. Parameter Source Confusion

Without explicit [FromQuery] or [FromRoute], multiple sources can conflict. Be explicit.

5. No Endpoint Organization

Putting all endpoints in Program.cs creates a massive file. Use static classes or extension methods to organize.

Practice Questions

1. What is a Minimal API?

A simplified ASP.NET Core approach for creating HTTP APIs without controllers, using lambda-based endpoint handlers.

2. How do you inject a service into a Minimal API endpoint?

Add the service as a parameter to the lambda. The DI container resolves it automatically.

3. What is the difference between Results.Ok and TypedResults.Ok?

TypedResults implements IResult and enables better OpenAPI metadata. Results is the main static factory.

4. How do you group related endpoints?

Use app.MapGroup("/prefix") to create a group with shared configuration (auth, tags, filters).

5. Challenge: Create a complete CRUD Minimal API for a todo list.

var todos = new List<Todo>();
var api = app.MapGroup("/api/todos");
api.MapGet("/", () => todos);
api.MapGet("/{id}", (int id) => todos.Find(t => t.Id == id) is Todo t ? Results.Ok(t) : Results.NotFound());
api.MapPost("/", (Todo todo) => { todo.Id = todos.Count + 1; todos.Add(todo); return Results.Created($"/api/todos/{todo.Id}", todo); });

FAQ

When should I use Minimal APIs over controllers?

For simple endpoints (microservices, health checks, small CRUD). Use controllers for complex apps with many related endpoints.

Can Minimal APIs support OpenAPI?

Yes. Add WithOpenApi() and WithName() for operation IDs. Add AddEndpointsApiExplorer() for Swagger.

Do Minimal APIs support authorization?

Yes. Add RequireAuthorization() to individual endpoints or groups.

How do I handle CORS with Minimal APIs?

Same as MVC: builder.Services.AddCors(), app.UseCors() in the pipeline.

Can I use EF Core with Minimal APIs?

Yes. Register DbContext in DI and inject it as a parameter in endpoint lambdas.

Mini Project: Todo Minimal API

Build a complete todo list Minimal API with CRUD and file storage.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var todos = new List<object>();
app.MapPost("/todos", (string title) => {
    todos.Add(new { Id = todos.Count + 1, Title = title, Done = false });
    return Results.Ok(todos.Last());
});
app.MapGet("/todos", () => todos);
app.MapDelete("/todos/{id}", (int id) => {
    todos.RemoveAll(t => t.Id == id);
    return Results.NoContent();
});
app.Run();

What's Next

ASP.NET Core SignalR ASP.NET Core Testing

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro