Moclawr.MinimalAPI 2.1.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package Moclawr.MinimalAPI --version 2.1.1
                    
NuGet\Install-Package Moclawr.MinimalAPI -Version 2.1.1
                    
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.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Moclawr.MinimalAPI" Version="2.1.1" />
                    
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.1
                    
#r "nuget: Moclawr.MinimalAPI, 2.1.1"
                    
#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.1
                    
#: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.1
                    
Install as a Cake Addin
#tool nuget:?package=Moclawr.MinimalAPI&version=2.1.1
                    
Install as a Cake Tool

Moclawr.MinimalAPI

NuGet

Overview

Moclawr.MinimalAPI is a powerful library for building clean, structured, and maintainable ASP.NET Core Minimal APIs for .NET 9. It provides a class-based approach to endpoint definition with built-in MediatR integration for implementing the CQRS pattern, making it easy to create scalable API applications with clear separation of concerns.

Key Features:

  • Strong typing for requests and responses
  • Smart automatic parameter binding with intelligent defaults
  • Enhanced OpenAPI documentation with automatic parameter detection
  • Rich SwaggerUI integration with custom styling and functionality
  • Standardized response handling
  • Support for versioning and authorization
  • Command/Query pattern support with automatic binding defaults

Getting Started

  1. Add a reference to the MinimalAPI project in your application.
  2. Register the MinimalAPI services in your Program.cs file.
  3. Create endpoint classes that inherit from EndpointBase.
  4. Map all endpoints in your Program.cs file.

Real-World Use Cases

Use Case 1: E-Commerce Product Catalog API

Perfect for building scalable product management APIs with rich filtering and search capabilities:

// Product search with advanced filtering
public class SearchProductsRequest : IQueryCollectionRequest<ProductDto>
{
    public string? SearchTerm { get; set; }
    public decimal? MinPrice { get; set; }
    public decimal? MaxPrice { get; set; }
    public List<int>? CategoryIds { get; set; }
    public List<string>? Tags { get; set; }
    public bool InStock { get; set; } = true;
    public int PageIndex { get; set; } = 0;
    public int PageSize { get; set; } = 20;
    public ProductSortBy SortBy { get; set; } = ProductSortBy.Name;
}

[OpenApiSummary("Search products with advanced filtering")]
[OpenApiParameter("searchTerm", typeof(string), Description = "Search in product name and description")]
[OpenApiParameter("minPrice", typeof(decimal), Description = "Minimum price filter", Example = 10.00)]
[OpenApiParameter("maxPrice", typeof(decimal), Description = "Maximum price filter", Example = 100.00)]
public class SearchProductsEndpoint(IMediator mediator) 
    : CollectionEndpointBase<SearchProductsRequest, ProductDto>(mediator)
{
    [HttpGet("api/products/search")]
    public override async Task<ResponseCollection<ProductDto>> HandleAsync(
        SearchProductsRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}

Use Case 2: User Management System

Ideal for authentication and user profile management with robust validation:

// User registration with validation
public class RegisterUserRequest : ICommand<RegisterUserResponse>
{
    [EmailAddress, Required]
    public string Email { get; set; } = string.Empty;
    
    [MinLength(8), Required]
    public string Password { get; set; } = string.Empty;
    
    [Required, MaxLength(100)]
    public string FullName { get; set; } = string.Empty;
    
    public string? PhoneNumber { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public List<string> Preferences { get; set; } = new();
}

[OpenApiSummary("Register a new user account")]
[OpenApiResponse(201, typeof(Response<RegisterUserResponse>), "User registered successfully")]
[OpenApiResponse(409, Description = "Email already exists")]
[OpenApiResponse(400, Description = "Validation failed")]
public class RegisterUserEndpoint(IMediator mediator)
    : SingleEndpointBase<RegisterUserRequest, RegisterUserResponse>(mediator)
{
    [HttpPost("api/auth/register")]
    public override async Task<Response<RegisterUserResponse>> HandleAsync(
        RegisterUserRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}

Use Case 3: Real-Time Dashboard API

Great for building analytics and monitoring dashboards with real-time data:

// Dashboard metrics with date range filtering
public class GetDashboardMetricsRequest : IQueryRequest<DashboardMetricsDto>
{
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public string TimeZone { get; set; } = "UTC";
    public List<string>? MetricTypes { get; set; }
    public DashboardView View { get; set; } = DashboardView.Summary;
    
    [FromHeader("X-Organization-Id")]
    public string? OrganizationId { get; set; }
}

[OpenApiSummary("Get dashboard metrics and analytics")]
[OpenApiParameter("startDate", typeof(DateTime), Description = "Start date for metrics (ISO 8601)")]
[OpenApiParameter("view", typeof(DashboardView), Description = "Dashboard view type", Example = DashboardView.Detailed)]
[Authorize(Policy = "DashboardAccess")]
public class GetDashboardMetricsEndpoint(IMediator mediator)
    : SingleEndpointBase<GetDashboardMetricsRequest, DashboardMetricsDto>(mediator)
{
    [HttpGet("api/dashboard/metrics")]
    public override async Task<Response<DashboardMetricsDto>> HandleAsync(
        GetDashboardMetricsRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}

Complete Setup Example

Step 1: Register Services in Program.cs

var builder = WebApplication.CreateBuilder(args);

// Register Minimal API services with enhanced SwaggerUI
builder.Services.AddMinimalApiWithSwaggerUI(
    title: "MLSolutions API",
    version: "v2.1.0",
    description: "Enterprise-grade API built with Moclawr.MinimalAPI framework featuring CQRS, MediatR integration, and comprehensive OpenAPI documentation",
    contactName: "MLSolutions Development Team",
    contactEmail: "dev@mlsolutions.com",
    contactUrl: "https://mlsolutions.com/support",
    licenseName: "MIT License",
    licenseUrl: "https://opensource.org/licenses/MIT",
    assemblies: [
        typeof(Program).Assembly,
        typeof(Application.Register).Assembly,
        typeof(Infrastructure.Register).Assembly,
        typeof(Domain.Register).Assembly
    ]
);

// Add authentication and authorization
builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options => { /* JWT config */ });
builder.Services.AddAuthorization();

// Register MediatR and other services
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(
    typeof(Application.Register).Assembly));

var app = builder.Build();

// Configure middleware pipeline
app.UseAuthentication();
app.UseAuthorization();

// Enable Swagger documentation in development
if (app.Environment.IsDevelopment())
{
    app.UseMinimalApiDocs(
        swaggerRoutePrefix: "api-docs",
        enableTryItOut: true,
        enableDeepLinking: true,
        enableFilter: true,
        enableValidator: true
    );
}

// Map all minimal API endpoints
app.MapMinimalEndpoints(
    typeof(Program).Assembly,
    typeof(Application.Register).Assembly
);

app.Run();

Step 2: SwaggerUI-Specific Features

Enhanced UI Configuration
// Advanced SwaggerUI configuration
app.UseMinimalApiSwaggerUI(
    routePrefix: "api-docs",           // Custom route prefix
    enableTryItOut: true,              // Enable "Try it out" by default
    enableDeepLinking: true,           // Enable deep linking
    enableFilter: true,                // Enable endpoint filtering
    enableValidator: false,            // Disable validator
    docExpansion: DocExpansion.List,   // Expand operations list
    defaultModelRendering: ModelRendering.Example, // Show examples
    persistAuthorization: true        // Remember auth tokens
);
Custom Styling and Assets

The SwaggerUI comes with enhanced styling and custom functionality:

Features:

  • Custom CSS: Modern gradient header, enhanced colors, better readability
  • Copy Buttons: Automatic copy buttons for code blocks
  • Enhanced Buttons: Styled "Try it out" and "Execute" buttons
  • Responsive Design: Better mobile and tablet experience
  • Custom JavaScript: Enhanced functionality and user experience

Step 3: Advanced Use Case Implementation

File Upload with Progress Tracking
public class UploadFileRequest : ICommand<UploadFileResponse>
{
    [FromForm]
    public IFormFile File { get; set; } = null!;
    
    [FromForm]
    public string? Description { get; set; }
    
    [FromForm]
    public List<string> Tags { get; set; } = new();
    
    [FromRoute]
    public int ProjectId { get; set; }
}

[OpenApiSummary("Upload file with metadata")]
[OpenApiResponse(201, typeof(Response<UploadFileResponse>), "File uploaded successfully")]
[OpenApiResponse(413, Description = "File too large")]
[OpenApiResponse(415, Description = "Unsupported file type")]
[Authorize]
public class UploadFileEndpoint(IMediator mediator)
    : SingleEndpointBase<UploadFileRequest, UploadFileResponse>(mediator)
{
    [HttpPost("api/projects/{projectId}/files")]
    [RequestSizeLimit(50_000_000)] // 50MB limit
    public override async Task<Response<UploadFileResponse>> HandleAsync(
        UploadFileRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}
Multiple File Upload
public class UploadMultipleFilesRequest : ICommand<UploadMultipleFilesResponse>
{
    [FromForm]
    public List<IFormFile> Files { get; set; } = new();
    
    [FromForm]
    public string Category { get; set; } = string.Empty;
    
    [FromForm]
    public bool GenerateThumbnails { get; set; } = true;
    
    [FromRoute]
    public int FolderId { get; set; }
}

[OpenApiSummary("Upload multiple files with batch processing")]
[OpenApiResponse(201, typeof(Response<UploadMultipleFilesResponse>), "Files uploaded successfully")]
[OpenApiResponse(400, Description = "Invalid file types or empty file list")]
public class UploadMultipleFilesEndpoint(IMediator mediator)
    : SingleEndpointBase<UploadMultipleFilesRequest, UploadMultipleFilesResponse>(mediator)
{
    [HttpPost("api/folders/{folderId}/files/batch")]
    public override async Task<Response<UploadMultipleFilesResponse>> HandleAsync(
        UploadMultipleFilesRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}
Mixed Form Data with File Upload
public class CreateProductWithImageRequest : ICommand<CreateProductResponse>
{
    [FromForm]
    public string Name { get; set; } = string.Empty;
    
    [FromForm]
    public decimal Price { get; set; }
    
    [FromForm]
    public string Description { get; set; } = string.Empty;
    
    [FromForm]
    public IFormFile? MainImage { get; set; }
    
    [FromForm]
    public List<IFormFile> GalleryImages { get; set; } = new();
    
    [FromForm]
    public List<string> Tags { get; set; } = new();
    
    [FromRoute]
    public int CategoryId { get; set; }
}

[OpenApiSummary("Create product with images")]
[OpenApiResponse(201, typeof(Response<CreateProductResponse>), "Product created with images")]
[OpenApiResponse(400, Description = "Validation failed or invalid image formats")]
public class CreateProductWithImageEndpoint(IMediator mediator)
    : SingleEndpointBase<CreateProductWithImageRequest, CreateProductResponse>(mediator)
{
    [HttpPost("api/categories/{categoryId}/products")]
    public override async Task<Response<CreateProductResponse>> HandleAsync(
        CreateProductWithImageRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}

Smart Parameter Binding Features

Automatic Request Body Detection

The framework automatically detects the appropriate request body format:

  • JSON Body: For commands without form data or file uploads
  • Form Data: For commands with IFormFile properties or [FromForm] attributes
  • Mixed Binding: Route parameters, query parameters, headers, and body/form data in the same request

Enhanced SwaggerUI Features

File Upload Support:

  • Drag & Drop Interface: Modern file upload UI in SwaggerUI
  • Multiple File Selection: Support for array/list of files
  • File Type Validation: Automatic MIME type detection and validation
  • Progress Indicators: Real-time upload progress display

Form Data Documentation:

  • Rich Schema Generation: Automatic form field documentation
  • File Upload Examples: Sample file upload requests
  • Mixed Content Support: JSON + file uploads in the same request

Production-Ready Features

Error Handling and Validation

The framework provides comprehensive error handling out of the box:

// Automatic validation error responses
public class CreateOrderRequest : ICommand<CreateOrderResponse>
{
    [Required, Range(1, int.MaxValue)]
    public int CustomerId { get; set; }
    
    [Required, MinLength(1)]
    public List<OrderItemDto> Items { get; set; } = new();
    
    [Required, RegularExpression(@"^[A-Z]{3}$")]
    public string CurrencyCode { get; set; } = "USD";
    
    [EmailAddress]
    public string? NotificationEmail { get; set; }
}

// Framework automatically returns 400 with detailed validation errors
// No additional validation code needed in the endpoint

Performance Optimization with Caching

public class GetPopularProductsRequest : IQueryCollectionRequest<ProductDto>
{
    public int CategoryId { get; set; }
    public int Count { get; set; } = 10;
    public TimeSpan CacheDuration { get; set; } = TimeSpan.FromHours(1);
}

[OpenApiSummary("Get popular products with intelligent caching")]
[ResponseCache(Duration = 3600, VaryByQueryKeys = new[] { "categoryId", "count" })]
public class GetPopularProductsEndpoint(IMediator mediator)
    : CollectionEndpointBase<GetPopularProductsRequest, ProductDto>(mediator)
{
    [HttpGet("api/categories/{categoryId}/products/popular")]
    public override async Task<ResponseCollection<ProductDto>> HandleAsync(
        GetPopularProductsRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}

Security and Rate Limiting

[OpenApiSummary("Send password reset email")]
[OpenApiResponse(200, Description = "Reset email sent if account exists")]
[EnableRateLimiting("auth-policy")]  // Custom rate limiting
public class SendPasswordResetEndpoint(IMediator mediator)
    : SingleEndpointBase<SendPasswordResetRequest, SendPasswordResetResponse>(mediator)
{
    [HttpPost("api/auth/reset-password")]
    public override async Task<Response<SendPasswordResetResponse>> HandleAsync(
        SendPasswordResetRequest req, CancellationToken ct)
        => await _mediator.Send(req, ct);
}

Step 4: Create Endpoint Classes with Enhanced Documentation

Command Endpoints with Rich SwaggerUI Documentation
[OpenApiSummary("Create a new todo", 
    Description = "Creates a new todo item with the provided details. Supports categorization and tagging.",
    Tags = new[] { "Todo Management", "CRUD Operations" })]
[OpenApiResponse(201, ResponseType = typeof(Response<CreateTodoResponse>), 
    Description = "Todo created successfully with generated ID")]
[OpenApiResponse(400, Description = "Invalid request data - validation failed")]
[OpenApiResponse(409, Description = "Todo with similar title already exists")]
public class CreateTodoEndpoint(IMediator mediator)
    : SingleEndpointBase<CreateTodoRequest, CreateTodoResponse>(mediator)
{
    [HttpPost("api/todos")]
    public override async Task<Response<CreateTodoResponse>> HandleAsync(
        CreateTodoRequest req,
        CancellationToken ct
    )
    {
        return await _mediator.Send(req, ct);
    }
}

The enhanced SwaggerUI will automatically show:

  • Rich Documentation: Detailed descriptions, examples, and response codes
  • Interactive Examples: "Try it out" functionality with sample data
  • Request Body Schema: Automatically generated from CreateTodoRequest
  • Response Examples: Sample responses for different status codes
  • Parameter Validation: Required/optional field indicators
Query Endpoints with Advanced Filtering UI
[OpenApiSummary("Get all todos with filtering", 
    Description = "Retrieves a paginated list of todos with advanced filtering, sorting, and search capabilities")]
[OpenApiParameter("search", typeof(string), Description = "Search term for filtering todos by title or description", Example = "grocery")]
[OpenApiParameter("pageSize", typeof(int), Description = "Number of items per page (max 100)", Example = 10)]
[OpenApiParameter("categoryIds", typeof(List<int>), Description = "Filter by specific category IDs", Example = new[] { 1, 2, 3 })]
[OpenApiResponse(200, ResponseType = typeof(ResponseCollection<TodoItemDto>), 
    Description = "Successfully retrieved todos with pagination metadata")]
[OpenApiResponse(400, Description = "Invalid pagination or filter parameters")]
public class GetAllTodosEndpoint(IMediator mediator)
    : CollectionEndpointBase<GetAllTodosRequest, TodoItemDto>(mediator)
{
    [HttpGet("api/todos")]
    public override async Task<ResponseCollection<TodoItemDto>> HandleAsync(
        GetAllTodosRequest req,
        CancellationToken ct
    )
    {
        return await mediator.Send(req, ct);
    }
}

SwaggerUI Advanced Features

Custom Theming and Branding

The SwaggerUI comes with a professional, modern theme:

/* Automatic features included */
- Gradient header with company branding
- Enhanced operation blocks with status-specific colors
- Modern button styling with hover effects
- Improved typography and spacing
- Mobile-responsive design
- Dark mode friendly colors

Enhanced Functionality

Automatic Features:

  • Copy to Clipboard: All code blocks get copy buttons
  • Request Duration Display: Shows API response times
  • Persistent Authorization: Remembers auth tokens across sessions
  • Deep Linking: Direct links to specific operations
  • Advanced Filtering: Search through endpoints
  • Example Generation: Automatic request/response examples

Security Integration

// SwaggerUI automatically detects and displays security requirements
[Authorize] // Automatically adds security icon and requirements
public class SecureEndpoint : SingleEndpointBase<SecureRequest, SecureResponse>
{
    // Security requirements automatically documented
}

Custom Examples and Documentation

[OpenApiParameter("userId", typeof(int), 
    Description = "Unique identifier for the user", 
    Example = 12345,
    Required = true)]
[OpenApiResponse(200, 
    ResponseType = typeof(UserProfileResponse),
    Description = "User profile retrieved successfully")]
public class GetUserProfileEndpoint : SingleEndpointBase<GetUserRequest, UserProfileResponse>
{
    // Rich documentation with examples automatically displayed in SwaggerUI
}

Integration with Other Moclawr Packages

This package works seamlessly with other packages in the Moclawr ecosystem:

  • Moclawr.Core: Leverages extension methods and utilities for enhanced functionality
  • Moclawr.Shared: Uses standardized response models and entity interfaces
  • Moclawr.Host: Perfect companion for complete API solutions with global exception handling
  • Moclawr.Services.Autofac: Compatible with Autofac dependency injection container
  • Moclawr.EfCore: Works with EF Core repositories in CQRS handlers
  • Moclawr.MongoDb: Supports MongoDB repositories in command/query handlers
  • Moclawr.Services.Caching: Integrates with caching strategies in endpoint handlers

Requirements

  • .NET 9.0 or higher
  • MediatR 12.2.0 or higher
  • Microsoft.AspNetCore.OpenApi 9.0.0 or higher
  • Swashbuckle.AspNetCore.SwaggerGen 8.1.2 or higher
  • Swashbuckle.AspNetCore.SwaggerUI 8.1.2 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 280 6/4/2025
2.1.8 141 6/4/2025
2.1.7 147 6/4/2025
2.1.6 148 6/4/2025
2.1.4 118 5/30/2025
2.1.3 137 5/30/2025
2.1.2 129 5/30/2025
2.1.1 142 5/28/2025
2.1.0 141 5/28/2025
2.0.1 65 5/24/2025
2.0.0 72 5/24/2025
1.0.3 68 5/24/2025
1.0.2.1 78 5/24/2025
1.0.2 144 5/22/2025
1.0.1 147 5/21/2025
1.0.0 147 5/19/2025

Added SwaggerUI support for enhanced API documentation experience.