dotnet-minimal-api-endpoints
Generates Minimal API endpoints following Microsoft's recommended approach. Creates fast, testable HTTP APIs with minimal code using MapGet/MapPost/MapPut/MapDelete. Preferred over controller-based APIs for new projects.
git clone --depth 1 https://github.com/ronnythedev/dotnet-clean-architecture-skills /tmp/dotnet-minimal-api-endpoints && cp -r /tmp/dotnet-minimal-api-endpoints/skills/07.2-dotnet-minimal-api-endpoints ~/.claude/skills/dotnet-minimal-api-endpointsSKILL.md
# Minimal API Endpoints Generator
## Overview
**Microsoft's recommended approach for new projects.** Minimal APIs provide a simplified, high-performance way to build HTTP APIs with less boilerplate than controllers.
### Benefits Over Controllers
- ✅ **Simpler syntax** - Less code, more productivity
- ✅ **Better performance** - Reduced overhead
- ✅ **Easier testing** - Testable handler methods
- ✅ **Modern approach** - Latest .NET features
- ✅ **Less ceremony** - No controller classes needed
## Quick Reference
| HTTP Method | Extension Method | Use Case |
|-------------|------------------|----------|
| `MapGet` | Read single/list | `app.MapGet("/users/{id}", ...)` |
| `MapPost` | Create | `app.MapPost("/users", ...)` |
| `MapPut` | Update (full) | `app.MapPut("/users/{id}", ...)` |
| `MapDelete` | Delete | `app.MapDelete("/users/{id}", ...)` |
---
## Endpoint Structure
```
/API/Endpoints/
├── {Feature}/
│ ├── {Feature}Endpoints.cs
│ └── Request{Action}{Entity}.cs
└── ...
```
---
## Template: Complete CRUD Endpoints
```csharp
// src/{name}.api/Endpoints/{Feature}/{Feature}Endpoints.cs
using {name}.application.{feature}.Create{Entity};
using {name}.application.{feature}.Delete{Entity};
using {name}.application.{feature}.Get{Entity}ById;
using {name}.application.{feature}.Get{Entities};
using {name}.application.{feature}.Update{Entity};
using {name}.infrastructure.authorization;
using MediatR;
using Microsoft.AspNetCore.Http.HttpResults;
namespace {name}.api.Endpoints.{Feature};
/// <summary>
/// Endpoints for {Entity} management
/// </summary>
public static class {Feature}Endpoints
{
/// <summary>
/// Maps all {Entity} endpoints
/// </summary>
public static RouteGroupBuilder Map{Feature}Endpoints(this IEndpointRouteBuilder routes)
{
var group = routes.MapGroup("/api/{entities}")
.WithTags("{Feature}")
.RequireAuthorization();
group.MapGet("/{id:guid}", GetById)
.WithName("Get{Entity}ById")
.WithSummary("Get {entity} by ID")
.Produces<{Entity}Response>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
group.MapGet("/", GetAll)
.WithName("GetAll{Entities}")
.WithSummary("Get all {entities}")
.Produces<IReadOnlyList<{Entity}ListResponse>>(StatusCodes.Status200OK);
group.MapPost("/", Create)
.WithName("Create{Entity}")
.WithSummary("Create new {entity}")
.RequireAuthorization(Permissions.{Entities}Write)
.Produces<Guid>(StatusCodes.Status201Created)
.Produces(StatusCodes.Status400BadRequest);
group.MapPut("/{id:guid}", Update)
.WithName("Update{Entity}")
.WithSummary("Update existing {entity}")
.RequireAuthorization(Permissions.{Entities}Write)
.Produces(StatusCodes.Status204NoContent)
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status400BadRequest);
group.MapDelete("/{id:guid}", Delete)
.WithName("Delete{Entity}")
.WithSummary("Delete {entity}")
.RequireAuthorization(Permissions.{Entities}Write)
.Produces(StatusCodes.Status204NoContent)
.Produces(StatusCodes.Status404NotFound);
return group;
}
// ═══════════════════════════════════════════════════════════════
// HANDLER METHODS
// ═══════════════════════════════════════════════════════════════
/// <summary>
/// Gets an {entity} by ID
/// </summary>
private static async Task<Results<Ok<{Entity}Response>, NotFound>> GetById(
Guid id,
ISender sender,
CancellationToken cancellationToken)
{
var query = new Get{Entity}ByIdQuery(id);
var result = await sender.Send(query, cancellationToken);
return result.IsSuccess
? TypedResults.Ok(result.Value)
: TypedResults.NotFound();
}
/// <summary>
/// Gets all {entities}
/// </summary>
private static async Task<Ok<IReadOnlyList<{Entity}ListResponse>>> GetAll(
ISender sender,
CancellationToken cancellationToken)
{
var query = new GetAll{Entities}Query();
var result = await sender.Send(query, cancellationToken);
return TypedResults.Ok(result.Value);
}
/// <summary>
/// Creates a new {entity}
/// </summary>
private static async Task<Results<Created<Guid>, BadRequest<Error>>> Create(
RequestCreate{Entity} request,
ISender sender,
CancellationToken cancellationToken)
{
var command = new Create{Entity}Command(
request.Name,
request.Description);
var result = await sender.Send(command, cancellationToken);
return result.IsSuccess
? TypedResults.Created($"/api/{entities}/{result.Value}", result.Value)
: TypedResults.BadRequest(result.Error);
}
/// <summary>
/// Updates an existing {entity}
/// </summary>
private static async Task<Results<NoContent, NotFound, BadRequest<Error>>> Update(
Guid id,
RequestUpdate{Entity} request,
ISender sender,
CancellationToken cancellationToken)
{
var command = new Update{Entity}Command(id, request.Name, request.Description);
var result = await sender.Send(command, cancellationToken);
if (result.IsFailure)
{
return result.Error.Code.Contains("NotFound")
? TypedResults.NotFound()
: TypedResults.BadRequest(result.Error);
}
return TypedResults.NoContent();
}
/// <summary>
/// Deletes an {entity}
/// </summary>
private static async Task<Results<NoContent, NotFound>> Delete(
Guid id,
ISender sender,
CancellationToken cancellationToken)
{
var command = new Delete{EntiScaffolds a complete .NET solution following Clean Architecture principles with proper layer separation (API, Application, Domain, Infrastructure). Creates project structure, dependency injection setup, and cross-cutting concerns configuration.
Generates CQRS Commands with Handlers, Validators, and Request DTOs following Clean Architecture patterns. Commands represent actions that modify state and return Result types for proper error handling.
Generates CQRS Queries with Handlers and Response DTOs for read operations. Uses Dapper for optimized read queries, bypassing the domain model for better performance.
Generates Domain Entities following DDD principles with factory methods, private setters, domain events, and proper encapsulation. Supports aggregate roots, child entities, and value objects.
Generates Repository interfaces and implementations following the Repository pattern. Provides data access abstraction for aggregate roots with EF Core implementations.
Generates Entity Framework Core configurations using Fluent API. Maps domain entities to database tables with proper relationships, constraints, and conventions.
Generates RESTful API Controllers with proper routing, versioning, authorization, and MediatR integration. Follows REST conventions and Clean Architecture patterns.
Implements the Result pattern for explicit error handling without exceptions. Provides Result, Result<T>, and Error types for clean, predictable control flow in domain-driven applications.