Skip to content

Working with Endpoint Definitions

David Kallesen edited this page Aug 17, 2026 · 2 revisions

πŸ›£οΈ Working with Endpoint Definitions

This guide explains the IEndpointDefinition pattern used by the generated minimal API endpoints.

🌟 Overview

The source generator creates structured endpoint definitions that implement the IEndpointDefinition interface. Each path segment gets its own definition class with route mapping, parameter binding, and OpenAPI metadata. All definition classes are emitted side by side in the shared Endpoints folder and namespace, since their type names are already segment-prefixed.

πŸ“‚ Generated Structure

For an API with /pets and /users path segments:

Generated/
└── Endpoints/
    β”œβ”€β”€ IEndpointDefinition.cs           # Shared interface
    β”œβ”€β”€ PetsEndpointDefinition.cs
    β”œβ”€β”€ UsersEndpointDefinition.cs
    β”œβ”€β”€ EndpointDefinitionExtensions.cs  # One Map{Segment}Endpoints() per segment
    └── EndpointMappingExtensions.cs     # MapApiEndpoints() β€” maps all segments

βš™οΈ Generated Code

πŸ”Œ IEndpointDefinition Interface

Generated once in the shared Endpoints namespace:

namespace MyApi.Generated.Endpoints;

[GeneratedCode("Atc.Rest.Api.SourceGenerator", "1.0.0")]
public interface IEndpointDefinition
{
    void DefineEndpoints(WebApplication app);
}

πŸ“‹ Endpoint Definition Class

Each path segment gets a definition class, all sharing the root Endpoints namespace:

namespace MyApi.Generated.Endpoints;

[GeneratedCode("Atc.Rest.Api.SourceGenerator", "1.0.0")]
public sealed class PetsEndpointDefinition : IEndpointDefinition
{
    internal const string ApiRouteBase = "/pets";

    public void DefineEndpoints(WebApplication app)
    {
        var pets = app
            .MapGroup(ApiRouteBase)
            .WithTags("Pets");

        pets
            .MapGet("/", ListPets)
            .WithName("ListPets")
            .WithSummary("List all pets")
            .Produces<List<Pet>>()
            .ProducesValidationProblem();

        pets
            .MapGet("{petId}", GetPetById)
            .WithName("GetPetById")
            .WithSummary("Get a pet by ID")
            .Produces<Pet>()
            .ProducesProblem(StatusCodes.Status404NotFound);

        pets
            .MapPost("/", CreatePet)
            .WithName("CreatePet")
            .WithSummary("Create a pet")
            .Produces<Pet>(StatusCodes.Status201Created)
            .ProducesValidationProblem();
    }

    internal async Task<IResult> ListPets(
        [FromServices] IListPetsHandler handler,
        [AsParameters] ListPetsParameters parameters,
        CancellationToken cancellationToken)
        => ListPetsResult.ToIResult(
            await handler.ExecuteAsync(parameters, cancellationToken));

    internal async Task<IResult> GetPetById(
        [FromServices] IGetPetByIdHandler handler,
        [AsParameters] GetPetByIdParameters parameters,
        CancellationToken cancellationToken)
        => GetPetByIdResult.ToIResult(
            await handler.ExecuteAsync(parameters, cancellationToken));

    // ... more endpoint methods ...
}

πŸ—ΊοΈ Endpoint Mapping Extensions

Two extension classes are generated, both in the root Endpoints namespace.

EndpointDefinitionExtensions exposes one Map{Segment}Endpoints() method per path segment, each instantiating that segment's definition class:

public static class EndpointDefinitionExtensions
{
    public static WebApplication MapPetsEndpoints(this WebApplication app)
    {
        new PetsEndpointDefinition().DefineEndpoints(app);
        return app;
    }

    public static WebApplication MapUsersEndpoints(this WebApplication app)
    {
        new UsersEndpointDefinition().DefineEndpoints(app);
        return app;
    }
}

EndpointMappingExtensions aggregates them into the single entry point you call from Program.cs:

public static class EndpointMappingExtensions
{
    public static WebApplication MapApiEndpoints(this WebApplication app)
    {
        app.MapPetsEndpoints();
        app.MapUsersEndpoints();
        return app;
    }
}

πŸ’‘ Call MapApiEndpoints() to register everything, or call an individual Map{Segment}Endpoints() when you need to map only part of the API.

πŸ”§ Configuration

UseMinimalApiPackage

Controls where the IEndpointDefinition interface comes from:

{
  "useMinimalApiPackage": "auto"
}
Value Behavior
"auto" Use Atc.Rest.MinimalApi package if referenced, otherwise generate locally (default)
"enabled" Always use from Atc.Rest.MinimalApi NuGet package (error if not referenced)
"disabled" Always generate the interface locally

UseValidationFilter

Adds FluentValidation filter to endpoint definitions:

{
  "useMinimalApiPackage": "enabled",
  "useValidationFilter": "enabled"
}

When enabled, endpoint definitions include .AddEndpointFilter<ValidationFilter<T>>() for request validation.

πŸš€ Program.cs

var builder = WebApplication.CreateBuilder(args);

// Register handlers from Domain project
builder.Services.AddApiHandlersFromDomain();

var app = builder.Build();

// Map all generated endpoints
app.MapApiEndpoints();

app.Run();

Polymorphic Endpoint Collection

Since all definition classes implement the shared IEndpointDefinition interface, you can collect and apply them dynamically:

// Discover and register all endpoint definitions
var endpointDefinitions = typeof(PetsEndpointDefinition).Assembly
    .GetTypes()
    .Where(t => typeof(IEndpointDefinition).IsAssignableFrom(t) && !t.IsInterface)
    .Select(Activator.CreateInstance)
    .Cast<IEndpointDefinition>();

foreach (var definition in endpointDefinitions)
{
    definition.DefineEndpoints(app);
}

πŸ“‹ Grouping Strategies

The subFolderStrategy setting controls how operations are grouped into endpoint definitions:

Strategy Grouping Example
"FirstPathSegment" (default) By first path segment /pets/* -> PetsEndpointDefinition
"OpenApiTag" By OpenAPI operation tag Tag pets -> PetsEndpointDefinition
{
  "subFolderStrategy": "FirstPathSegment"
}

➑️ Next Steps

🏠 Home

πŸ’Ό Why This Tool?

πŸ“– Getting Started

βš™οΈ Features

🌐 Frontend

πŸ“‹ Reference


πŸ”— Resources

Clone this wiki locally