Moclawr.MinimalAPI
2.1.2
See the version list below for details.
dotnet add package Moclawr.MinimalAPI --version 2.1.2
NuGet\Install-Package Moclawr.MinimalAPI -Version 2.1.2
<PackageReference Include="Moclawr.MinimalAPI" Version="2.1.2" />
<PackageVersion Include="Moclawr.MinimalAPI" Version="2.1.2" />
<PackageReference Include="Moclawr.MinimalAPI" />
paket add Moclawr.MinimalAPI --version 2.1.2
#r "nuget: Moclawr.MinimalAPI, 2.1.2"
#:package Moclawr.MinimalAPI@2.1.2
#addin nuget:?package=Moclawr.MinimalAPI&version=2.1.2
#tool nuget:?package=Moclawr.MinimalAPI&version=2.1.2
Moclawr.MinimalAPI
Overview
Moclawr.MinimalAPI provides a class-based approach to ASP.NET Core Minimal APIs with automatic endpoint discovery, MediatR integration, and enhanced OpenAPI documentation. It bridges the gap between minimal APIs and traditional controller-based APIs by offering a structured, object-oriented approach while maintaining the performance benefits of minimal APIs.
Features
- Class-Based Endpoints: Object-oriented endpoint design with base classes
- Automatic Discovery: Auto-registration of endpoint classes from assemblies
- MediatR Integration: Built-in CQRS pattern support with command/query separation
- Advanced API Versioning: Multiple versioning strategies (URL segment, query string, headers, media type)
- Enhanced OpenAPI Documentation: Rich SwaggerUI with automatic schema generation
- Intelligent Request Binding: Automatic parameter binding from route, query, body, form, and headers
- Type-Safe Endpoints: Strongly-typed request and response handling
- Flexible Response Types: Support for single items, collections, and custom response wrappers
- Attribute-Based Configuration: Declarative endpoint configuration with attributes
- Custom Authentication: Built-in authorization and authentication support
Installation
Install the package via NuGet Package Manager:
dotnet add package Moclawr.MinimalAPI
Quick Start
1. Register Services
In your Program.cs
:
using MinimalAPI;
var builder = WebApplication.CreateBuilder(args);
// Add MinimalAPI with enhanced documentation
builder.Services.AddMinimalApiWithSwaggerUI(
title: "My API",
version: "v1",
description: "Comprehensive API built with MinimalAPI framework"
);
var app = builder.Build();
// Auto-discover and map all endpoints
app.MapMinimalEndpoints(typeof(Program).Assembly);
// Enable documentation
if (app.Environment.IsDevelopment())
{
app.UseMinimalApiDocs();
}
app.Run();
2. Create Your First Endpoint
using MinimalAPI.Endpoints;
using MinimalAPI.Attributes;
using MediatR;
[OpenApiSummary("Get user by ID", "Retrieves a specific user by their unique identifier")]
[ApiVersion(1)]
public class GetUserEndpoint(IMediator mediator)
: ItemEndpointBase<GetUserQuery, UserDto>(mediator)
{
[HttpGet("/api/users/{id}")]
public override async Task<Response<UserDto>> HandleAsync(
GetUserQuery request, CancellationToken ct)
{
return await _mediator.Send(request, ct);
}
}
3. Define Request Models
using MediatR;
using MinimalAPI.Attributes;
public record GetUserQuery : IRequest<Response<UserDto>>
{
[FromRoute]
public int Id { get; init; }
}
public record CreateUserRequest : IRequest<Response<UserDto>>
{
[FromBody]
public string Name { get; init; } = string.Empty;
[FromBody]
public string Email { get; init; } = string.Empty;
}
Core Concepts
Endpoint Base Classes
The framework provides several base classes for different endpoint patterns:
SingleEndpointBase<TRequest, TResponse>
For endpoints returning a single item:
public class CreateUserEndpoint(IMediator mediator)
: SingleEndpointBase<CreateUserCommand, UserDto>(mediator)
{
[HttpPost("/api/users")]
public override async Task<Response<UserDto>> HandleAsync(
CreateUserCommand request, CancellationToken ct)
{
return await _mediator.Send(request, ct);
}
}
CollectionEndpointBase<TRequest, TResponse>
For endpoints returning collections:
public class GetUsersEndpoint(IMediator mediator)
: CollectionEndpointBase<GetUsersQuery, UserDto>(mediator)
{
[HttpGet("/api/users")]
public override async Task<ResponseCollection<UserDto>> HandleAsync(
GetUsersQuery request, CancellationToken ct)
{
return await _mediator.Send(request, ct);
}
}
EndpointBase<TRequest, TResponse, TResponseWrapper>
For custom response types:
public class CustomEndpoint(IMediator mediator)
: EndpointBase<CustomRequest, CustomData, CustomResponse>(mediator)
{
[HttpPost("/api/custom")]
public override async Task<CustomResponse> HandleAsync(
CustomRequest request, CancellationToken ct)
{
return await _mediator.Send(request, ct);
}
}
Request Binding
The framework automatically binds request data from various sources:
Attribute-Based Binding
public class UpdateUserCommand
{
[FromRoute("id")]
public int UserId { get; set; }
[FromBody]
public string Name { get; set; }
[FromQuery]
public bool NotifyUser { get; set; }
[FromHeader("X-Client-Version")]
public string? ClientVersion { get; set; }
[FromServices]
public ILogger<UpdateUserCommand> Logger { get; set; }
}
Smart Default Binding
- Route parameters: Automatically bound by name
- Query parameters: For GET requests and query strings
- Request body: For POST/PUT/PATCH with JSON content
- Form data: For multipart/form-data and form submissions
- Headers: For custom header values
API Versioning
Comprehensive versioning support with multiple strategies:
Configuration
var versioningOptions = new DefaultVersioningOptions
{
Prefix = "v",
DefaultVersion = 1,
SupportedVersions = [1, 2, 3],
// Multiple reading strategies
ReadingStrategy = VersionReadingStrategy.UrlSegment |
VersionReadingStrategy.QueryString |
VersionReadingStrategy.Header,
QueryParameterName = "version",
VersionHeaderName = "X-API-Version",
AssumeDefaultVersionWhenUnspecified = true
};
builder.Services.AddMinimalApiWithSwaggerUI(
versioningOptions: versioningOptions
);
Version-Specific Endpoints
[ApiVersion(1)]
public class GetUsersV1Endpoint : CollectionEndpointBase<GetUsersQuery, UserDto>
{
[HttpGet("/api/users")]
public override async Task<ResponseCollection<UserDto>> HandleAsync(...)
{
// Version 1 implementation
}
}
[ApiVersion(2)]
public class GetUsersV2Endpoint : CollectionEndpointBase<GetUsersQueryV2, UserDtoV2>
{
[HttpGet("/api/users")]
public override async Task<ResponseCollection<UserDtoV2>> HandleAsync(...)
{
// Version 2 implementation with enhanced features
}
}
Accessing Versions
# URL Segment
GET /api/v1/users
GET /api/v2/users
# Query Parameter
GET /api/users?version=1
GET /api/users?version=2
# Header
GET /api/users
X-API-Version: 1
# Media Type
GET /api/users
Accept: application/json;version=1
Enhanced OpenAPI Documentation
Rich Documentation Attributes
[OpenApiSummary("Create a new user", "Creates a new user account with the provided information")]
[OpenApiParameter("name", "User's full name", required: true, example: "John Doe")]
[OpenApiParameter("email", "User's email address", required: true, example: "john@example.com")]
[OpenApiResponse(201, "User created successfully", typeof(UserDto))]
[OpenApiResponse(400, "Invalid user data provided")]
[OpenApiResponse(409, "User with this email already exists")]
public class CreateUserEndpoint : SingleEndpointBase<CreateUserCommand, UserDto>
{
[HttpPost("/api/users")]
public override async Task<Response<UserDto>> HandleAsync(...)
{
return await _mediator.Send(request, ct);
}
}
Automatic Schema Generation
The framework automatically generates OpenAPI schemas for:
- Request/response types
- Enum values with descriptions
- File upload parameters
- Pagination metadata
- Error response formats
Feature-Based Tagging
Endpoints are automatically tagged based on namespace structure:
Namespace: MyApp.Features.Users.Commands
Generated Tags: ["Users", "Users Commands"]
Namespace: MyApp.Features.Orders.Queries
Generated Tags: ["Orders", "Orders Queries"]
File Upload Support
Single File Upload
public class UploadFileCommand
{
[FromForm]
public IFormFile File { get; set; }
[FromForm]
public string Description { get; set; }
}
public class UploadFileEndpoint(IMediator mediator)
: SingleEndpointBase<UploadFileCommand, FileDto>(mediator)
{
[HttpPost("/api/files")]
public override async Task<Response<FileDto>> HandleAsync(...)
{
return await _mediator.Send(request, ct);
}
}
Multiple File Upload
public class UploadFilesCommand
{
[FromForm]
public List<IFormFile> Files { get; set; }
[FromForm]
public string Folder { get; set; }
}
Authentication and Authorization
Endpoint-Level Security
[Authorize("AdminPolicy")]
public class DeleteUserEndpoint : SingleEndpointBase<DeleteUserCommand, Response>
{
[HttpDelete("/api/users/{id}")]
public override async Task<Response> HandleAsync(...)
{
return await _mediator.Send(request, ct);
}
}
Custom Authorization
[RequireRole("Admin", "Manager")]
[RequireClaim("permission", "users:delete")]
public class DeleteUserEndpoint : SingleEndpointBase<DeleteUserCommand, Response>
{
// Implementation
}
Advanced Features
Custom Endpoint Filters
public class LoggingEndpointFilter : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
var logger = context.HttpContext.RequestServices
.GetRequiredService<ILogger<LoggingEndpointFilter>>();
logger.LogInformation("Executing endpoint: {Endpoint}",
context.HttpContext.Request.Path);
var result = await next(context);
logger.LogInformation("Completed endpoint: {Endpoint}",
context.HttpContext.Request.Path);
return result;
}
}
Response Caching
[ResponseCache(Duration = 300)] // Cache for 5 minutes
public class GetUserEndpoint : SingleEndpointBase<GetUserQuery, UserDto>
{
[HttpGet("/api/users/{id}")]
public override async Task<Response<UserDto>> HandleAsync(...)
{
return await _mediator.Send(request, ct);
}
}
Rate Limiting
[RateLimit("UserEndpoints", Window = "1m", Limit = 60)]
public class CreateUserEndpoint : SingleEndpointBase<CreateUserCommand, UserDto>
{
[HttpPost("/api/users")]
public override async Task<Response<UserDto>> HandleAsync(...)
{
return await _mediator.Send(request, ct);
}
}
Integration Examples
With Entity Framework Core
public class GetUsersHandler(IQueryRepository<User, int> repository)
: IRequestHandler<GetUsersQuery, ResponseCollection<UserDto>>
{
public async Task<ResponseCollection<UserDto>> Handle(
GetUsersQuery request, CancellationToken cancellationToken)
{
var users = await repository.GetPagedListAsync<UserDto>(
request.Page,
request.PageSize,
filter: u => u.IsActive,
orderBy: q => q.OrderBy(u => u.Name),
cancellationToken: cancellationToken
);
return ResponseHelper.CreateSuccessCollection(users);
}
}
With Caching
public class GetUserHandler(
IQueryRepository<User, int> repository,
ICacheService cache)
: IRequestHandler<GetUserQuery, Response<UserDto>>
{
public async Task<Response<UserDto>> Handle(
GetUserQuery request, CancellationToken cancellationToken)
{
var cacheKey = $"user:{request.Id}";
var cachedUser = await cache.GetAsync<UserDto>(cacheKey);
if (cachedUser != null)
{
return ResponseHelper.CreateSuccess(cachedUser);
}
var user = await repository.GetByIdAsync<UserDto>(
request.Id, cancellationToken: cancellationToken);
if (user != null)
{
await cache.SetAsync(cacheKey, user, TimeSpan.FromMinutes(15));
}
return ResponseHelper.CreateSuccess(user);
}
}
Integration with Other Moclawr Packages
This package works seamlessly with other packages in the Moclawr ecosystem:
- Moclawr.Core: Uses extension methods and utilities for enhanced functionality
- Moclawr.Shared: Integrates with response models and entity interfaces
- Moclawr.Host: Perfect companion for global exception handling and infrastructure
- Moclawr.EfCore and Moclawr.MongoDb: Works with repository patterns for data access
- Moclawr.Services.Caching: Enables response caching for API endpoints
- Moclawr.Services.External: Integrates external services in endpoint handlers
- Moclawr.Services.Autofac: Enhanced dependency injection for endpoint registration
Requirements
- .NET 9.0 or higher
- MediatR 12.4.1 or higher
- Microsoft.AspNetCore.OpenApi 9.0.5 or higher
- Swashbuckle.AspNetCore 7.2.0 or higher
License
This package is licensed under the MIT License.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- MediatR (>= 12.2.0)
- Microsoft.AspNetCore.OpenApi (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.5)
- Moclawr.Core (>= 2.1.0)
- Moclawr.Shared (>= 2.0.1)
- Swashbuckle.AspNetCore.SwaggerGen (>= 8.1.2)
- Swashbuckle.AspNetCore.SwaggerUI (>= 8.1.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
2.1.9 | 282 | 6/4/2025 |
2.1.8 | 142 | 6/4/2025 |
2.1.7 | 148 | 6/4/2025 |
2.1.6 | 149 | 6/4/2025 |
2.1.4 | 119 | 5/30/2025 |
2.1.3 | 138 | 5/30/2025 |
2.1.2 | 130 | 5/30/2025 |
2.1.1 | 143 | 5/28/2025 |
2.1.0 | 142 | 5/28/2025 |
2.0.1 | 66 | 5/24/2025 |
2.0.0 | 73 | 5/24/2025 |
1.0.3 | 69 | 5/24/2025 |
1.0.2.1 | 79 | 5/24/2025 |
1.0.2 | 145 | 5/22/2025 |
1.0.1 | 148 | 5/21/2025 |
1.0.0 | 148 | 5/19/2025 |
Added SwaggerUI support for enhanced API documentation experience.