minimal-api-organization

star 0

Expert in organizing ASP.NET Core Minimal APIs for production apps - extension methods, TypedResults, endpoint groups, Swagger documentation, and model organization

erloon By erloon schedule Updated 2/14/2026

name: minimal-api-organization description: Expert in organizing ASP.NET Core Minimal APIs for production apps - extension methods, TypedResults, endpoint groups, Swagger documentation, and model organization

What I Do

  • Organize minimal API endpoints into clean, maintainable structure
  • Replace inline lambdas with extension method registrations
  • Convert Results to TypedResults for compile-time safety and auto OpenAPI docs
  • Implement comprehensive Swagger documentation (XML comments, typed results, summaries)
  • Organize models into Requests, Responses, and DTOs with validation and documentation
  • Extract handlers into testable static methods
  • Group related endpoints with MapGroup for DRY configuration

When to Use Me

Trigger phrases:

  • "Add API endpoint"
  • "Organize minimal APIs"
  • "Create new endpoint group"
  • "Refactor Program.cs endpoints"
  • "Set up endpoint registration"
  • "Clean up API routes"
  • "Add endpoint for [resource]"
  • "Improve Swagger documentation"
  • "Add XML comments to API"

Use this skill when working with ASP.NET Core minimal API endpoints, restructuring Program.cs, implementing new API routes, or improving API documentation in .NET projects.


Core Principles

1. Extension Methods for Endpoint Registration

Organize endpoints into separate files with extension methods.

File structure:

backend/Aimy.API/
├── Program.cs           # Clean entry point
├── Aimy.API.csproj      # XML Doc configuration
├── Endpoints/
│   ├── AuthEndpoints.cs
│   └── TodoEndpoints.cs
└── Models/
    ├── Requests/        # Request models (records)
    ├── Responses/       # Response models (classes)
    └── DTOs/            # Shared DTOs

2. Comprehensive Documentation

  • Enable XML documentation in .csproj.
  • Use WithSummary, WithDescription for endpoints.
  • Use XML comments (///) for handler methods and models.
  • Explicitly define Produces<T> and Accepts<T> where TypedResults inference isn't enough.

3. TypedResults Instead of Results

TypedResults provides:

  • Automatic OpenAPI/Swagger documentation
  • Compile-time type checking
  • Simpler unit testing

4. Separate Handlers from Registration

Extract lambda handlers into named static methods for testability and readability.

5. Group Related Endpoints

Use MapGroup to avoid route prefix repetition and apply shared configuration (e.g., Tags, Auth).


Configuration Setup

1. Project File (.csproj)

Enable XML documentation generation to feed Swagger.

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn> <!-- Suppress missing comment warnings if desired -->
</PropertyGroup>

2. Program.cs (Swagger Setup)

Configure Swagger to use XML comments and handle Authentication.

builder.Services.AddSwaggerGen(options =>
{
    // Include XML comments
    var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    if (File.Exists(xmlPath))
    {
        options.IncludeXmlComments(xmlPath);
    }

    // Auth Configuration (Bearer)
    options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
    {
        Name = "Authorization",
        Type = Microsoft.OpenApi.Models.SecuritySchemeType.Http,
        Scheme = "bearer",
        BearerFormat = "JWT",
        In = Microsoft.OpenApi.Models.ParameterLocation.Header,
        Description = "JWT Authorization header using the Bearer scheme."
    });

    options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
    {
        {
            new Microsoft.OpenApi.Models.OpenApiSecurityScheme
            {
                Reference = new Microsoft.OpenApi.Models.OpenApiReference
                {
                    Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            Array.Empty<string>()
        }
    });
});

Note: If using Swashbuckle.AspNetCore > 10.x, use Microsoft.OpenApi.Models namespace directly as it depends on Microsoft.OpenApi 2.x which supports Reference. Avoid mixing Microsoft.OpenApi 3.x manually if Swashbuckle depends on 2.x.


Implementation Pattern

Endpoint Definition

// Endpoints/TodoEndpoints.cs
public static class TodoEndpoints
{
    public static void MapTodoEndpoints(this IEndpointRouteBuilder app)
    {
        var group = app.MapGroup("/todos")
            .WithTags("Todos")
            .RequireAuthorization();
        
        group.MapPost("/", CreateTodo)
            .WithName("CreateTodo")
            .WithSummary("Create a new todo item")
            .WithDescription("Creates a new todo item and returns the created resource.")
            .Produces<TodoResponse>(StatusCodes.Status201Created)
            .Produces<ErrorResponse>(StatusCodes.Status400BadRequest);
    }
    
    /// <summary>
    /// Creates a new todo item
    /// </summary>
    /// <param name="request">Creation request model</param>
    /// <param name="db">Database context</param>
    /// <returns>Created todo item</returns>
    /// <remarks>
    /// Sample request:
    /// 
    ///     POST /todos
    ///     {
    ///        "title": "Buy milk",
    ///        "isComplete": false
    ///     }
    /// </remarks>
    private static async Task<Results<Created<TodoResponse>, BadRequest<ErrorResponse>>> CreateTodo(
        CreateTodoRequest request,
        TodoDb db)
    {
        if (string.IsNullOrEmpty(request.Title))
        {
            return TypedResults.BadRequest(new ErrorResponse { Message = "Title is required" });
        }

        var todo = new Todo { Title = request.Title };
        db.Todos.Add(todo);
        await db.SaveChangesAsync();
        
        return TypedResults.Created($"/todos/{todo.Id}", new TodoResponse(todo));
    }
}

Model Organization

Request Model (Record):

// Models/Requests/CreateTodoRequest.cs
using System.ComponentModel.DataAnnotations;

/// <summary>
/// Request model for creating a todo item
/// </summary>
public record CreateTodoRequest
{
    /// <summary>
    /// Title of the todo item
    /// </summary>
    /// <example>Buy groceries</example>
    [Required]
    public required string Title { get; init; }
    
    /// <summary>
    /// Whether the item is completed
    /// </summary>
    /// <example>false</example>
    public bool IsComplete { get; init; }
}

Response Model (Class/Record):

// Models/Responses/TodoResponse.cs
/// <summary>
/// Response model for todo item
/// </summary>
public class TodoResponse
{
    /// <summary>
    /// Unique identifier
    /// </summary>
    /// <example>1</example>
    public int Id { get; set; }
    
    /// <summary>
    /// Title of the item
    /// </summary>
    /// <example>Buy groceries</example>
    public required string Title { get; set; }
}

TypedResults Reference

Response TypedResult Usage
200 + data Task<Ok<T>> GET success
201 Created Task<Created<T>> POST create
204 No Content Task<NoContent> PUT/DELETE success
404 NotFound Not found
400 BadRequest<ErrorResponse> Validation error
401 UnauthorizedHttpResult Auth failure
403 ForbidHttpResult Permission failure
500 ProblemHttpResult Server error

Union pattern:

static async Task<Results<Ok<Todo>, NotFound, BadRequest>> GetTodo(int id, TodoDb db)

Anti-Patterns & Fixes

Avoid Problem Solution
Inline lambdas Untestable, cluttered Static extension methods
Results (untyped) No OpenAPI inference TypedResults
Missing XML docs Empty Swagger UI Enable GenerateDocumentationFile
Swashbuckle + MS.OpenApi v3 Version conflict Use transitive dependency (v2.x)
Magic strings in routes Refactoring errors MapGroup & NameOf
Logic in handlers Tightly coupled Inject Services/Mediator

Testing

Test handlers directly without HTTP:

var result = await TodoEndpoints.GetTodoById(1, inMemoryDb);
Assert.IsType<Ok<Todo>>(result.Result);
Install via CLI
npx skills add https://github.com/erloon/Aimy --skill minimal-api-organization
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator