Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/masastack/MASA.Framework/llms.txt

Use this file to discover all available pages before exploring further.

MASA Framework’s Minimal APIs layer wraps ASP.NET Core’s minimal API infrastructure with a convention-driven routing system. Instead of writing individual app.MapGet(...) calls for every endpoint, you inherit from ServiceBase, name your methods following HTTP-verb prefixes, and let the framework discover and register all routes automatically — including path segmentation, version injection, and optional parameter appending.

Installation

dotnet add package Masa.Contrib.Service.MinimalAPIs

Setup

Replace the standard WebApplication.Create flow with MASA’s AddServices extension. It scans all assemblies for ServiceBase subclasses and returns a configured WebApplication:
var builder = WebApplication.CreateBuilder(args);

// AddServices scans assemblies, registers ServiceBase subclasses, and
// returns the built WebApplication
var app = builder.AddServices(options =>
{
    options.Prefix = "api";
    options.Version = "v1";
    options.PluralizeServiceName = true;
    options.AutoAppendId = true;
});

app.MapMasaMinimalAPIs();  // materialize all discovered routes
app.Run();

Convention-Based HTTP Method Detection

The framework inspects each public method name and maps it to an HTTP verb:
Method prefixHTTP verb
Get, Select, FindGET
Post, Add, Create, Upsert, InsertPOST
Put, Update, ModifyPUT
Delete, RemoveDELETE
Any method whose name doesn’t match a known prefix is mapped according to MapHttpMethodsForUnmatched (default: POST).

Route Format

Routes follow this pattern:
{Prefix}/{Version}/{ServiceName}/{MethodSuffix}
For a service class named OrderService with defaults (api, v1, pluralized):
MethodRoute
GetListAsync()GET /api/v1/orders
GetAsync(Guid id)GET /api/v1/orders/{id}
AddAsync(...)POST /api/v1/orders
DeleteAsync(Guid id)DELETE /api/v1/orders/{id}
The framework strips the HTTP-verb prefix from the method name and uses the remainder as the route suffix. A no-suffix method (e.g., GetAsync) maps to the service root path. When AutoAppendId is true and a parameter named id exists, /{id} is appended automatically.

Basic Service Example

public class OrderService : ServiceBase
{
    // GET /api/v1/orders
    public async Task<List<Order>> GetListAsync(
        [FromServices] IOrderRepository repo)
        => await repo.GetListAsync();

    // GET /api/v1/orders/{id}
    public async Task<Order?> GetAsync(
        Guid id,
        [FromServices] IOrderRepository repo)
        => await repo.FindAsync(id);

    // POST /api/v1/orders
    public async Task AddAsync(
        [FromBody] CreateOrderRequest request,
        [FromServices] IEventBus eventBus)
        => await eventBus.PublishAsync(new CreateOrderCommand(request));

    // PUT /api/v1/orders/{id}
    public async Task UpdateAsync(
        Guid id,
        [FromBody] UpdateOrderRequest request,
        [FromServices] IEventBus eventBus)
        => await eventBus.PublishAsync(new UpdateOrderCommand(id, request));

    // DELETE /api/v1/orders/{id}
    public async Task DeleteAsync(Guid id) { }
}

Global Route Options (ServiceGlobalRouteOptions)

Passed to AddServices(options => ...) to set defaults for all services:
PropertyTypeDefaultDescription
Prefixstring"api"URL prefix segment
Versionstring"v1"Version segment
AutoAppendIdbooltrueAppends /{id} when an id parameter exists
PluralizeServiceNamebooltruePluralises OrderServiceorders
DisableTrimMethodPrefixboolfalseKeeps the HTTP-verb prefix in the route segment
EnablePropertyboolfalseExposes public properties as additional endpoints
MapHttpMethodsForUnmatchedstring[]["POST"]Verbs used for prefix-unmatched methods

Per-Service Route Options

Each ServiceBase subclass can override global options via its RouteOptions property:
public class ProductService : ServiceBase
{
    public ProductService()
    {
        RouteOptions.Prefix = "internal";
        RouteOptions.Version = "v2";
        RouteOptions.PluralizeServiceName = false;
        RouteOptions.AutoAppendId = false;
        RouteOptions.DisableAutoMapRoute = false;
    }

    // GET /internal/v2/product/list
    public Task<List<Product>> GetListAsync() => ...;
}

Attribute-Based Route Overrides

[RoutePattern]

Override the generated route for a single method. Set StartWithBaseUri = true to prefix with the service’s base URI:
public class OrderService : ServiceBase
{
    [RoutePattern("/orders/export", StartWithBaseUri = false)]
    public async Task<FileResult> ExportAsync() => ...;

    [RoutePattern("history", StartWithBaseUri = true)]
    public async Task<List<Order>> GetHistoryAsync() => ...;
    // → GET /api/v1/orders/history
}

[IgnoreRoute]

Exclude a method from auto-registration entirely:
public class OrderService : ServiceBase
{
    [IgnoreRoute]
    public string BuildInternalKey(Guid id) => $"order:{id}";
}

Adding Authorization, Rate Limiting, and Filters

ServiceBase exposes RouteHandlerBuilder — an Action<RouteHandlerBuilder> that is applied to every endpoint registered by the service. Use it to attach endpoint metadata:
public class OrderService : ServiceBase
{
    public OrderService()
    {
        RouteHandlerBuilder = builder => builder
            .RequireAuthorization()
            .RequireRateLimiting("fixed");
    }

    public Task<List<Order>> GetListAsync() => ...;
    public Task AddAsync([FromBody] CreateOrderRequest req) => ...;
}
For per-method authorization, use standard ASP.NET Core attributes:
public class OrderService : ServiceBase
{
    [Authorize(Roles = "admin")]
    public Task DeleteAsync(Guid id) { return Task.CompletedTask; }
}

Disabling Auto-Mapping

Set DisableAutoMapRoute = true on a service to skip all automatic route registration and fall back to manual app.Map* calls:
public class LegacyService : ServiceBase
{
    public LegacyService() => RouteOptions.DisableAutoMapRoute = true;
}

Build docs developers (and LLMs) love