Skip to content

feat: Minimal API integration — map commands and queries to HTTP endpoints (NetEvolve.Pulse.AspNetCore) #140

@samtrion

Description

@samtrion

User Story

As a developer building ASP.NET Core Minimal API applications with Pulse, I want IEndpointRouteBuilder extension methods that map mediator commands and queries directly to HTTP endpoints, so that I can eliminate the boilerplate of writing controller actions or endpoint lambdas that only forward to IMediator.


Background

A common pattern in Minimal API projects is:

app.MapPost("/orders", async (CreateOrderCommand cmd, IMediator mediator, CancellationToken ct) =>
    Results.Ok(await mediator.SendAsync<CreateOrderCommand, OrderCreated>(cmd, ct)));

This pattern is repeated for every command and query. An IEndpointRouteBuilder integration generates these routes from CQRS message types, following conventions, and keeps the registration layer concise.


Requirements

  • Provide a new NuGet package NetEvolve.Pulse.AspNetCore targeting net8.0, net9.0, net10.0.
  • Define the following extension methods on IEndpointRouteBuilder:
    // Map a command to a POST endpoint
    RouteHandlerBuilder MapCommand<TCommand, TResponse>(
        this IEndpointRouteBuilder endpoints,
        string pattern)
        where TCommand : ICommand<TResponse>;
    
    // Map a void command to a POST endpoint
    RouteHandlerBuilder MapCommand<TCommand>(
        this IEndpointRouteBuilder endpoints,
        string pattern)
        where TCommand : ICommand<Void>;
    
    // Map a query to a GET endpoint
    RouteHandlerBuilder MapQuery<TQuery, TResponse>(
        this IEndpointRouteBuilder endpoints,
        string pattern)
        where TQuery : IQuery<TResponse>;
  • Each generated endpoint:
    • Binds the request body (for commands) or query string / route parameters (for queries) using the default Minimal API model binding.
    • Calls the corresponding IMediator method (SendAsync or QueryAsync).
    • Returns Results.Ok(response) on success.
    • Returns Results.NoContent() for void commands (ICommand<Void>).
    • Propagates CancellationToken from the HTTP request.
  • All registered endpoints must be compatible with Microsoft.AspNetCore.OpenApi (WithOpenApi() chainable).
  • The package must reference NetEvolve.Pulse.Extensibility and Microsoft.AspNetCore.Http.Abstractions.
  • No dependency on NetEvolve.Pulse itself — the mediator is resolved from DI at request time.

Acceptance Criteria

  • NetEvolve.Pulse.AspNetCore package builds on all three target frameworks.
  • MapCommand<TCommand, TResponse> registers a POST endpoint that dispatches via IMediator.SendAsync.
  • MapCommand<TCommand> registers a POST endpoint that returns 204 No Content for void commands.
  • MapQuery<TQuery, TResponse> registers a GET endpoint that dispatches via IMediator.QueryAsync.
  • Endpoints correctly propagate CancellationToken.
  • Generated endpoints are compatible with WithOpenApi() and produce correct OpenAPI metadata.
  • Unit tests verify route registration and HTTP result types.
  • Integration tests verify end-to-end HTTP dispatch through WebApplicationFactory<T>.
  • XML documentation is provided for all public members.

Out of Scope

Metadata

Metadata

Labels

type:featureIndicates a new feature or enhancement to be added.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions