Документация

Koto.Api.AspNetCore

Транспорт-независимая интеграция ASP.NET Core — Minimal API, MVC или любой хост.

Что вы получаете

  • ToHttpResult() / ToHttpResultAsync()Result<T>IResult (Minimal API)
  • ToActionResult() / ToActionResultAsync()Result<T>ActionResult<T> (MVC)
  • KotoProblemDetails — RFC 7807 Problem Details из одной или нескольких Error (несколько ошибок превращаются в validation problem details со словарём errors по полям)
  • KotoHttpErrorOptions — расширяемый реестр Error.Code → HTTP-статус

Быстрый старт

builder.Services.AddKotoAspNetCore(); // опционально: o => o.Map("payments.gateway-failed", 502)

Minimal API:

app.MapPost("/orders", (CreateOrderCommand cmd, ICqrsDispatcher dispatcher, HttpContext ctx, CancellationToken ct)
    => dispatcher.SendAsync(cmd, ct).ToHttpResultAsync(ctx));

MVC-контроллер:

[HttpPost]
public async Task<ActionResult<OrderDto>> Create(CreateOrderCommand cmd, CancellationToken ct)
    => (await _dispatcher.SendAsync(cmd, ct)).ToActionResult(this);

Маппинг кодов статуса

Порядок резолва: точный код → пользовательские правила → суффикс → префикс → дефолт для field-ошибок → fallback.

ПравилоСтатус
*.not-found404
*.already-*, *.conflict409
*.unauthorized401
*.forbidden403
general.*, validation.*, Error.Field != null400
всё остальное422 (fallback, настраивается)

Немаппленные бизнес-ошибки — это 422, никогда не 500: неуспешный Result — нарушение правила, на которое клиент может реагировать; 500 зарезервирован для необработанных исключений.

Настройка:

builder.Services.AddKotoAspNetCore(o => o
    .Map("subscription.payment-failed", StatusCodes.Status502BadGateway) // точное совпадение, высший приоритет
    .MapSuffix(".expired", StatusCodes.Status410Gone)
    .MapPrefix("quota.", StatusCodes.Status429TooManyRequests)
    .Map(e => e.Code.Contains(".locked-") ? StatusCodes.Status423Locked : null));