MiniMap is a handy Roslyn source generator that removes the boilerplate from ASP.NET Core Minimal API route registration.
Instead of manually writing app.MapGet("/path", handler) calls, just decorate your endpoint classes and let MiniMap handle the rest.
dotnet add package Duyda.MiniMap
using MiniMap;
namespace MyApi;
[MapGet("/api/users/{name}")]
[Authorize]
public static partial class GetUserEndpoint
{
public static string Handle(string name)
{
return $"User {name}";
}
}And MiniMap generates a Map() method to register the route for you:
// <auto-generated />
/// <summary>
/// Auto-generated Map method to register endpoint route by MiniMap.
/// </summary>
using global::Microsoft.AspNetCore.Builder;
namespace MyApi;
public static partial class GetUser
{
public static void Map(global::Microsoft.AspNetCore.Routing.IEndpointRouteBuilder builder)
{
builder.MapGet("/api/users/{name}", global::MyApi.GetUser.Handle)
.RequireAuthorization();
}
}Register it in Program.cs:
var app = WebApplication.CreateBuilder(args).Build();
GetUser.Map(app);
app.Run();| Attribute | Behaviour |
|---|---|
[MapGet], [MapPost], [MapPut], [MapDelete], [MapPatch] |
Map an HTTP method + route pattern to your handler |
[AllowAnonymous] |
Skip auth on the endpoint |
[Authorize] |
Require authorization |
[DisableAntiforgery] |
Disable antiforgery (useful for API-only endpoints) |
Multiple HTTP verbs on one endpoint? Just stack attributes:
[MapGet("/api/multiple-verbs"), MapPost, MapPut, MapDelete, MapPatch]
public static partial class MultipleVerbsEndpoint
{
public static void Handle() { }
}MiniMap looks for a HandleAsync() or Handle() method in your class. HandleAsync() takes priority if both exist.
You're right, it's a common pattern to do:
public interface IEndpoint
{
// expose stuffs here so you can write a general helper to register route on this interface
}Then a helper scans for implementations, instantiates them, and calls Map() on each. It works, but it means reflection at startup (or you wire it yourself), and allocated instances you don't need.
I personally like to keep it static, no new, no constructor and no state because there's no reason to instantiate a class. Minimal API lets you do DI through the method itself. And you also get the benefit of organizing everything in one single place: the route attribute, the handler logic, the generated registration code, request/response DTOs, validator class, etc...
MIT — see LICENSE.