Skip to main content

IEndpoint

Namespace: RA.Utilities.Api.Abstractions

The primary purpose of the IEndpoint interface is to organize and declutter API endpoint registration in an ASP.NET Core application. As an API grows, defining all the routes directly in the Program.cs file can make it messy and difficult to maintain.

The IEndpoint interface introduces a clean, discoverable pattern to solve this problem by allowing you to keep each endpoint in its own feature-focused file, mapped into the shared route group identified by its IEndpointGroup.

⚙️ How It Works​

The workflow is straightforward:

1. Implement the Interface​

You create a class for a specific endpoint (e.g., GetProductsEndpoint) and implement the IEndpoint interface with two static members:

  • GroupName — the name of the IEndpointGroup this endpoint belongs to.
  • MapEndpoint — receives the group's RouteGroupBuilder and the optional ApiVersionSet passed to MapEndpoints, and defines the routes, just as you would in Program.cs. Groups usually apply the version set themselves; the parameter lets an endpoint apply or override its own.
// Features/Products/GetProductsEndpoint.cs
using Asp.Versioning.Builder;
using Microsoft.AspNetCore.Routing;
using RA.Utilities.Api.Abstractions;

internal sealed class GetProductsEndpoint : IEndpoint
{
public static string GroupName => "Products";

public static void MapEndpoint(RouteGroupBuilder group, ApiVersionSet? apiVersionSet = null)
{
group.MapGet("/", () =>
{
// Logic to get all products
return Results.Ok("All products");
});

group.MapGet("/{id}", (int id) =>
{
// Logic to get a single product
return Results.Ok($"Product {id}");
});
}
}

2. Map the Routes​

After building the web application (var app = builder.Build();), you call the generated app.MapEndpoints() extension method. The source generator that ships with this package discovers your IEndpoint implementations at compile time and invokes each MapEndpoint with the RouteGroupBuilder of the group matching its GroupName, forwarding the ApiVersionSet passed to MapEndpoints.

// Program.cs

using Asp.Versioning;
using Asp.Versioning.Builder;

var builder = WebApplication.CreateBuilder(args);

// Required when endpoints apply an ApiVersionSet.
builder.Services.AddApiVersioning();

var app = builder.Build();

// Maps all groups and endpoints discovered at compile time
app.MapEndpoints(app.NewApiVersionSet()
.HasApiVersion(new ApiVersion(1))
.ReportApiVersions()
.Build());

app.Run();

Call app.MapEndpoints() without arguments when the API does not use versioning.

By following this pattern, you keep your Program.cs file clean and maintainable, while your endpoint definitions remain neatly organized by feature.

🧭 Compile-Time Validation​

When the GroupName is a compile-time constant, the generator validates it against the discovered groups at build time:

  • EPMG001 — two IEndpointGroup implementations declare the same GroupName.
  • EPMG002 — an IEndpoint references a GroupName no group declares.

Names computed at runtime (e.g. typeof(X).Name) are resolved at startup instead; a mismatch then throws an InvalidOperationException naming the endpoint type and the missing group key.