ModEndpoints provides various base endpoint types to organize ASP.NET Core Minimal APIs in the REPR (Request - Endpoint - Response) pattern. It shapes Minimal APIs into components encapsulating configuration, automatic request validation, request handling, and, depending on endpoint type, response mapping.
- REPR Pattern Implementation: Organizes Minimal APIs into Request, Endpoint and Response components.
- Seamless Integration: Fully compatible with ASP.NET Core Minimal APIs, supporting configurations, parameter binding, authentication, OpenAPI tooling, endpoint filters, route groups, etc.
- Auto-Discovery and Registration: Automatically discovers and registers endpoints and route groups.
- FluentValidation Support: Built-in validation using FluentValidation; requests are automatically validated if a validator is registered.
- Dependency Injection: Supports constructor-based dependency injection in endpoint implementation types.
- Type-Safe Responses: Provides response type safety in request handlers.
- Purpose: Enables full flexibility and capability of Minimal APIs within a structured approach.
- Usage: Suitable for implementing any Minimal API in endpoint format, from simple to complex scenarios.
- Package:
ModEndpoints.Core
- Purpose: Converts business results into standardized HTTP status codes and response formats, ensuring consistent and type-safe API behavior.
- Usage: Perfect for centralizing and abstracting the logic of converting business results into HTTP responses.
- Package:
ModEndpoints
- Purpose: Returns raw business results directly within an HTTP 200 OK response without additional formatting.
- Usage: Ideal for internal API layers or scenarios where the raw business result is sufficient for the client.
- Package:
ModEndpoints
- Purpose: Designed for simplifying remote service consumption only with knowledge of remote service base address and request model.
- Usage: Works in conjunction with the
ModEndpoints.RemoteServicespackage on client side to abstract HTTP plumbing while calling remote ServiceEndpoints. - Package:
ModEndpoints
Note: For detailed information on each endpoint type, refer to the Endpoint Types documentation.
Each endpoint must implement two virtual methods:
-
Configure: Invoked during application startup to define the route and HTTP method along with any additional configuration endpoint requires. It begins with calling input parameter
builder's methods likeMapGet,MapPost, etc., to specify the route pattern. The returnedRouteHandlerBuilderfrom the Map[HttpVerb] method can then be used for further endpoint customization. -
HandleAsync: Contains the logic to handle incoming requests. Called after the request is validated (if applicable).
Note: Dependencies resolved from constructor are not available during configuration. To access a service from dependency injection in the configuration phase, use the
ServiceProviderproperty of the configuration context parameter provided to theConfiguremethod.
Note:
ServiceEndpointprovides a default implementation for theConfiguremethod, and only requiresHandleAsyncmethod implementation.
- ModEndpoints.Core: Provides
MinimalEndpointstructure and contains the base implementations for organizing Minimal APIs in the REPR format. - ModEndpoints: Provides
WebResultEndpoint,BusinessResultEndpoint, andServiceEndpointstructures. - ModEndpoints.RemoteServices: Offers client implementations for
ServiceEndpointto facilitate remote service consumption. - ModEndpoints.RemoteServices.Core: Contains interfaces required for
ServiceEndpointrequest models.
dotnet add package ModEndpointsNote: To use only MinimalEndpoints, you can install the
ModEndpoints.Corepackage.
In your Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddModEndpointsFromAssemblyContaining<MyEndpoint>();
//Validation
builder.Services.AddValidatorsFromAssemblyContaining<MyValidator>(includeInternalTypes: true);
var app = builder.Build();
app.MapModEndpoints();
app.Run();Note: If you are using the
ModEndpoints.Corepackage, replaceAddModEndpointsFromAssemblyContainingwithAddModEndpointsCoreFromAssemblyContainingandMapModEndpointswithMapModEndpointsCore.
A MinimalEndpoint is the most straighforward way to define a Minimal API in REPR format.
Configuration of each endpoint implementation starts with calling one of the MapGet, MapPost, MapPut, MapDelete and MapPatch methods with a route pattern string. The return from any of these methods, a RouteHandlerBuilder instance, can be used to further customize the endpoint similar to a Minimal API.
The request is processed in 'HandleAsync' method. Request is passed to handler method as parameter after validation (if a validator is registered for request model). Handler method returns a response model or a string or a Minimal API IResult based response.
public record HelloWorldRequest(string Name);
internal class HelloWorldRequestValidator : AbstractValidator<HelloWorldRequest>
{
public HelloWorldRequestValidator()
{
RuleFor(x => x.Name).NotEmpty().MinimumLength(3).MaximumLength(50);
}
}
internal class HelloWorld
: MinimalEndpoint<HelloWorldRequest, IResult>
{
protected override void Configure(
EndpointConfigurationBuilder builder,
ConfigurationContext<EndpointConfigurationParameters> configurationContext)
{
builder.MapGet("MinimalEndpoints/HelloWorld/{Name}")
.Produces<string>();
}
protected override Task<IResult> HandleAsync(HelloWorldRequest req, CancellationToken ct)
{
return Task.FromResult(Results.Ok($"Hello, {req.Name}."));
}
}The GetWeatherForecast example from the .NET Core Web API project template can be rewritten using MinimalEndpoints in the REPR format as shown below:
internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
internal class GetWeatherForecast : MinimalEndpoint<WeatherForecast[]>
{
private static readonly string[] _summaries = ["Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];
protected override void Configure(
EndpointConfigurationBuilder builder,
ConfigurationContext<EndpointConfigurationParameters> configurationContext)
{
builder.MapGet("/weatherforecast")
.WithName("GetWeatherForecast")
.WithTags("WeatherForecastWebApi");
}
protected override Task<WeatherForecast[]> HandleAsync(CancellationToken ct)
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
_summaries[Random.Shared.Next(_summaries.Length)]
))
.ToArray();
return Task.FromResult(forecast);
}
}A WebResultEndpoint can be utilized to abstract the logic for converting business results into HTTP responses of endpoints. Configuration and request handling is similar to MinimalEndpoint, but a WebResultEndpoint handler method also has the benefit of having a strongly typed return while having potential to return different HTTP response codes according to business result state.
This sample demonstrates a GET endpoint with basic configuration and without any request model binding. Business result instance returned from handler method is converted to a Minimal API IResult based response by WebResultEndpoint before being sent to client.
public record ListBooksResponse(List<ListBooksResponseItem> Books);
public record ListBooksResponseItem(Guid Id, string Title, string Author, decimal Price);
internal class ListBooks(ServiceDbContext db)
: WebResultEndpointWithEmptyRequest<ListBooksResponse>
{
protected override void Configure(
EndpointConfigurationBuilder builder,
ConfigurationContext<EndpointConfigurationParameters> configurationContext)
{
builder.MapGet("/books")
.Produces<ListBooksResponse>();
}
protected override async Task<Result<ListBooksResponse>> HandleAsync(
CancellationToken ct)
{
var books = await db.Books
.Select(b => new ListBooksResponseItem(
b.Id,
b.Title,
b.Author,
b.Price))
.ToListAsync(ct);
return new ListBooksResponse(Books: books);
}
}For documents detailing other features and functionalities, refer to the following:
- Parameter Binding
- Request Validation
- Route Groups
- Disabling Components
- Open API Documentation
- Handling Files
- Endpoint Types:
- Result Pattern Integration
- IAsyncEnumerable Response
- WebResultEndpoint Response Mapping
- ServiceEndpoint Clients
ShowcaseWebApi project demonstrates all endpoint types in action and also API documentation with Swagger and Swashbuckle:
MinimalEnpointsamples are in Customers subfolder,WebResultEndpointsamples are in Books subfolder,BusinessResultEndpointsamples are in Stores subfolder,ServiceEndpointsamples are in StoresWithServiceEndpoint subfolder.
ServiceEndpointClient project demonstrates a client application consuming remote ServiceEndpoints.
WeatherForecastWebApi project demonstrates how GetWeatherForecast Minimal API in ASP.NET Core Web API project template can be written using MinimalEndpoints. Also demostrates API documentation with Scalar and OpenAPI.
Under load tests with 100 virtual users:
- MinimalEndpoints perform nearly the same (~1-2%) as Minimal APIs,
- WebResultEndpoints introduce a slight overhead (~2-3%) compared to Minimal APIs in terms of requests per second.
The web apis called for tests, perform only in-process operations like resolving dependency, validating input, calling local methods with no network or disk I/O.
See test results under BenchmarkFiles folder of BenchmarkWebApi project for detailed results and test scripts.