Moclawr.MinimalAPI 2.1.2

There is a newer version of this package available.
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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Moclawr.MinimalAPI" Version="2.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Moclawr.MinimalAPI" Version="2.1.2" />
                    
Directory.Packages.props
<PackageReference Include="Moclawr.MinimalAPI" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Moclawr.MinimalAPI --version 2.1.2
                    
#r "nuget: Moclawr.MinimalAPI, 2.1.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Moclawr.MinimalAPI@2.1.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Moclawr.MinimalAPI&version=2.1.2
                    
Install as a Cake Addin
#tool nuget:?package=Moclawr.MinimalAPI&version=2.1.2
                    
Install as a Cake Tool

Moclawr.MinimalAPI

NuGet

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.