/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
$ npx -y skills add managedcode/dotnet-skills --skill minimal-apis --agent claude-codeHow 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.mdname: 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
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
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.
Repo: managedcode/dotnet-skills
Other skills on dotnet-skills.
- /aspnet-core
Build, debug, modernize, or review ASP.NET Core applications with correct hosting, middleware, security, configuration, logging, and deployment patterns on current .NET. USE FOR: working on ASP.NET Core apps, services, or middleware; changing auth, routing, configuration,
Open skill - /aspire
Build, upgrade, and operate Aspire 13.4.x C# or TypeScript application hosts with the current CLI, AppHost, ServiceDefaults, integrations, dashboard, testing, MCP, and deployment patterns for distributed apps. USE FOR: Aspire.AppHost.Sdk, Aspire.Hosting.*,
Open skill - /azure-functions
Build, review, or migrate Azure Functions in .NET with correct execution model, isolated worker setup, bindings, DI, and Durable Functions patterns. USE FOR: working on Azure Functions in .NET; migrating from the in-process model to the isolated worker model; adding Durable
Open skill - /blazor
Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices. USE FOR: building interactive web UIs with C# instead of JavaScript; choosing between Server, WebAssembly, or
Open skill - /entity-framework6
Maintain or migrate EF6-based applications with realistic guidance on what to keep, what to modernize, and when EF Core is or is not the right next step. USE FOR: EF6 codebases; runtime versus ORM migration decisions; EDMX, code-first, ObjectContext, and legacy data-access
Open skill - /entity-framework-core
Design, tune, or review EF Core data access with proper modeling, migrations, query translation, performance, and lifetime management for modern .NET applications. USE FOR: DbContext, migrations, model configuration, EF queries, tracking, loading, performance, transactions, and
Open skill

