Functional.AspNetCore
UnambitiousFx.Functional.AspNetCore converts Result and Maybe<T> to HTTP responses for both Minimal APIs and MVC.
Introduction
Use this package to keep application logic in Result/Maybe form and map outcomes to HTTP consistently at the API
boundary.
Core Concepts
- Domain and application services return
ResultorMaybe<T>. - Transport mapping is centralized through adapters (
ToHttpResultandToActionResult). - Failure-to-status mapping remains explicit and customizable.
Install
dotnet add package UnambitiousFx.Functional.AspNetCore
Setup
Register services once:
builder.Services.AddResultHttp();
Simple Example
Namespace: UnambitiousFx.Functional.AspNetCore.Http
using UnambitiousFx.Functional.AspNetCore.Http;
app.MapGet("/users/{id:guid}", async (Guid id, IUserService service) =>
await service.GetUserAsync(id).ToHttpResult());
app.MapGet("/profiles/{id:guid}", async (Guid id, IProfileService service) =>
await service.TryGetProfileAsync(id).ToHttpResult());
app.MapPost("/users", async (CreateUserRequest request, IUserService service) =>
await service.CreateAsync(request).ToCreatedHttpResult(user => $"/users/{user.Id}"));
Advanced Concepts
- HTTP Mapping Model and Defaults
- Custom Mappers and Policy Composition
- Minimal API Patterns
- MVC and Controller Patterns
MVC Controllers
Namespace: UnambitiousFx.Functional.AspNetCore.Mvc
using UnambitiousFx.Functional.AspNetCore.Mvc;
[ApiController]
[Route("api/users")]
public sealed class UsersController : ControllerBase
{
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id, [FromServices] IUserService service)
=> await service.GetUserAsync(id).ToActionResult();
}
Default Error Mapping
Built-in failure mappings:
ValidationFailure-> 400NotFoundFailure-> 404UnauthorizedFailure-> 401UnauthenticatedFailure-> 403ConflictFailure-> 409ExceptionalFailure-> 500- unhandled failures -> 500