OneOf to IResult
Convert OneOf<T1,T2,...> discriminated unions to IResult in a single call β HTTP status codes are inferred from error type names and HttpStatusCode tags.
// In Minimal API endpoints
app.MapGet("/users/{id}", async (int id) =>
(await _service.GetUserAsync(id)).ToIResult());
app.MapPost("/users", async (CreateUserRequest req) =>
(await _service.CreateAsync(req)).ToPostResult()); // 201 Created on success
Setup β add only the arities you use:
Without the corresponding attribute that arity's[assembly: GenerateOneOf2ExtensionsAttribute] // OneOf<T1,T2>.ToIResult() [assembly: GenerateOneOf3ExtensionsAttribute] // OneOf<T1,T2,T3>.ToIResult() [assembly: GenerateOneOf4ExtensionsAttribute] // OneOf<T1,T2,T3,T4>.ToIResult().ToIResult()extension is not generated.
9.4.1. OneOf<T1,T2>.ToIResult()
OneOf<NotFoundError, User> result = await _service.GetAsync(id);
return result.ToIResult(); // 404 or 200
9.4.2. OneOf<T1,T2,T3>.ToIResult()
OneOf<ValidationError, ConflictError, User> result = await _service.CreateAsync(request);
return result.ToIResult(); // 422 or 409 or 200
9.4.3. OneOf<T1,T2,T3,T4>.ToIResult()
OneOf<ValidationError, UnauthorizedError, NotFoundError, Order> result =
await _service.GetOrderAsync(id);
return result.ToIResult(); // 422 or 401 or 404 or 200
9.4.4. HTTP Method Variants
Use typed variants for non-GET endpoints to get the correct success status:
| Method | Success status | Typical use |
|---|---|---|
.ToIResult() |
200 OK | GET |
.ToPostResult() |
201 Created | POST |
.ToPutResult() |
200 OK | PUT / PATCH |
.ToDeleteResult() |
204 No Content | DELETE |
app.MapPost("/orders", async (req) => (await _svc.CreateAsync(req)).ToPostResult());
app.MapPut("/orders/{id}", async (id, req) => (await _svc.UpdateAsync(id, req)).ToPutResult());
app.MapDelete("/orders/{id}", async (id) => (await _svc.DeleteAsync(id)).ToDeleteResult());
9.4.5. Error β HTTP Status Mapping
Status codes are resolved in order of precedence:
HttpStatusCodetag set on the error object at construction (domain errors set this automatically)- Type-name heuristic β
NotFoundErrorβ 404,ValidationErrorβ 422,ConflictErrorβ 409, etc. - Default β 400 Bad Request
// Domain errors set HttpStatusCode at construction β no configuration needed
public class NotFoundError : Reason<NotFoundError> // β 404
public class ValidationError : Reason<ValidationError> // β 422
public class ConflictError : Reason<ConflictError> // β 409
public class UnauthorizedError : Reason<UnauthorizedError> // β 401
public class ForbiddenError : Reason<ForbiddenError> // β 403
// Custom error with explicit tag
public class PaymentRequiredError : Error
{
public PaymentRequiredError() => this.WithTag(HttpStatusCode.PaymentRequired);
}