Skip to content
Development
Skill

/minimal-apis

Design and implement Minimal APIs in ASP.NET Core using handler-first endpoints, route groups, filters, and lightweight composition suited to modern .NET services. USE FOR: building new HTTP APIs in ASP.NET Core; creating lightweight microservices; choosing between Minimal APIs

From plugin
dotnet-skills
466200 skills50 agents
Install
$ npx -y skills add managedcode/dotnet-skills --skill minimal-apis --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/minimal-apis

Context preview

The summary Claude sees to decide when to auto-load this skill.

Design and implement Minimal APIs in ASP.NET Core using handler-first endpoints, route groups, filters, and lightweight composition suited to modern .NET services. USE FOR: building new HTTP APIs in ASP.NET Core; creating lightweight microservices; choosing between Minimal APIs

SKILL.md

minimal-apis.SKILL.md
name: minimal-apis
description: "Design and implement Minimal APIs in ASP.NET Core using handler-first endpoints, route groups, filters, and lightweight composition suited to modern .NET services. USE FOR: building new HTTP APIs in ASP.NET Core; creating lightweight microservices; choosing between Minimal APIs and controllers. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made."
compatibility: "Requires ASP.NET Core 6+, preferably .NET 8+ for full features."

Minimal APIs

Trigger On

  • building new HTTP APIs in ASP.NET Core
  • creating lightweight microservices
  • choosing between Minimal APIs and controllers
  • organizing endpoints with route groups
  • implementing validation and filters

Documentation

  • [Minimal APIs Overview](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-10.0)
  • [Minimal API Tutorial](https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-10.0)
  • [Filters in Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/min-api-filters?view=aspnetcore-10.0)
  • [OpenAPI Support](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/overview?view=aspnetcore-10.0)
  • [Route Groups](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/route-handlers?view=aspnetcore-10.0#route-groups)

References

  • [patterns.md](references/patterns.md) - detailed route groups, filters, TypedResults patterns, parameter binding, error handling, and testing
  • [anti-patterns.md](references/anti-patterns.md) - common Minimal API mistakes to avoid

When to Use Minimal APIs vs Controllers

| Use Minimal APIs | Use Controllers | |------------------|-----------------| | New projects | Existing MVC/API projects | | Microservices | Complex model binding | | Simple CRUD APIs | OData, JsonPatch | | Lightweight handlers | Heavy use of attributes | | .NET 8+ projects | Need `[ApiController]` features |

Workflow

1. **Define endpoints directly in Program.cs** (for small APIs) 2. **Use route groups** for related endpoints 3. **Move handlers to separate classes** as the API grows 4. **Apply filters** for cross-cutting concerns 5. **Use TypedResults** for type-safe responses 6. **Generate OpenAPI docs** with `.WithOpenApi()`

Current Upstream Notes

  • `dotnet/aspnetcore` `v10.0.10` is servicing; it does not change the Minimal API route-group/filter/TypedResults model, but it fixes nullable `DescriptionAttribute` handling and duplicate XML documentation IDs in OpenAPI generation.
  • The July 2026 `aspnetcore-10.0` overview still routes lightweight HTTP APIs here. Use the dedicated Minimal API pages when exact OpenAPI, filter, or parameter-binding behavior matters.

Basic Patterns

Simple Endpoints

var app = builder.Build();

app.MapGet("/", () => "Hello World");

app.MapGet("/products/{id}", (int id) => Results.Ok(new { Id = id }));

app.MapPost("/products", (Product product) => Results.Created($"/products/{product.Id}", product));

TypedResults (Strongly-Typed)

app.MapGet("/products/{id}", Results<Ok<Product>, NotFound> (int id, AppDb db) =>
{
    var product = db.Products.Find(id);
    return product is not null
        ? TypedResults.Ok(product)
        : TypedResults.NotFound();
});

Dependency Injection

app.MapGet("/products", async (IProductService service) =>
{
    return await service.GetAllAsync();
});

// Or with [FromServices] for clarity
app.MapGet("/products", async ([FromServices] IProductService service) =>
    await service.GetAllAsync());

Route Groups

Basic Grouping

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

products.MapGet("/", GetAll);
products.MapGet("/{id}", GetById);
products.MapPost("/", Create);
products.MapPut("/{id}", Update);
products.MapDelete("/{id}", Delete);

Groups with Shared Configuration

var api = app.MapGroup("/api")
    .RequireAuthorization()
    .AddEndpointFilter<ValidationFilter>();

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

var orders = api.MapGroup("/orders")
    .WithTags("Orders")
    .RequireAuthorization("AdminOnly");

Endpoint Filters

Inline Filter

app.MapGet("/products/{id}", (int id) => Results.Ok(id))
    .AddEndpointFilter(async (context, next) =>
    {
        var id = context.GetArgument<int>(0);
        if (id <= 0)
            return Results.BadRequest("Invalid ID");

        return await next(context);
    });

Class-Based Filter

public class ValidationFilter<T> : IEndpointFilter where T : class
{
    public async ValueTask<object?> InvokeAsync(
        EndpointFilterInvocationContext context,
        EndpointFilterDelegate next)
    {
        var argument = context.Arguments
            .OfType<T>()
            .FirstOrDefault();

        if (argument is null)
            return Results.BadRequest("Invalid request body");

        var validator = context.HttpContext.RequestServices
            .GetService<IValidator<T>>();

        if (validator is not null)
        {
            var result = await validator.ValidateAsync(argument);
            if (!result.IsValid)
                return Results.ValidationProblem(result.ToDictionary());
        }

        return await next(context);
    }
}

// Usage
products.MapPost("/", Create)
    .AddEndpointFilter<ValidationFilter<CreateProductRequest>>();

Global Filters via Root Group

// All endpoints inherit filters from root group
var root = app.MapGroup("")
    .AddEndpointFilter<LoggingFilter>()
    .AddEndpointFilter<ErrorHandlingFilter>();

root.MapGet("/health", () => Results.Ok());
root.MapGroup("/api/products").MapGet("/", GetProducts);

Organizing Larger APIs

Extension Method Pattern

Read more
Ships withdotnet-skills

Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.

Get the whole plugin

Other skills on dotnet-skills.