API Reference
Complete reference for all Pragmatic.Result types and methods.
Core Types
Section titled “Core Types”Result<TValue, TError>
Section titled “Result<TValue, TError>”A discriminated union representing either a success with a value or a failure with an error.
public readonly struct Result<TValue, TError> : IResultBase where TError : IErrorFactory Methods
Section titled “Factory Methods”| Method | Description |
|---|---|
Success(TValue value) | Creates a successful result with the given value |
Failure(TError error) | Creates a failed result with the given error |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
IsSuccess | bool | True if the result is successful |
IsFailure | bool | True if the result is a failure |
Value | TValue | The success value (throws if failure) |
Error | TError | The error (throws if success) |
Safe Access Methods
Section titled “Safe Access Methods”| Method | Description |
|---|---|
TryGetValue(out TValue? value) | Returns true and sets value if successful |
TryGetError(out TError? error) | Returns true and sets error if failed |
GetValueOrDefault(TValue fallback) | Returns value if success, otherwise fallback |
GetValueOrDefault(Func<TError, TValue> factory) | Returns value if success, or factory result |
GetValueOrThrow() | Returns value or throws with error details |
Pattern Matching
Section titled “Pattern Matching”| Method | Description |
|---|---|
Match<T>(onSuccess, onFailure) | Executes function based on state, returns result |
Match(onSuccess, onFailure) | Executes action based on state |
Transformation (Railway-Oriented)
Section titled “Transformation (Railway-Oriented)”| Method | Description |
|---|---|
Map<TNew>(Func<TValue, TNew>) | Transforms success value, preserves error |
MapError<TNewError>(Func<TError, TNewError>) | Transforms error, preserves success |
Bind<TNew>(Func<TValue, Result<TNew, TError>>) | Chains to another Result-returning function |
Validation
Section titled “Validation”| Method | Description |
|---|---|
Ensure(predicate, errorFactory) | Validates success value, converts to failure if predicate fails |
Side Effects (don’t change result)
Section titled “Side Effects (don’t change result)”| Method | Description |
|---|---|
Tap(Action<TValue>) | Executes action on success, returns same result |
OnSuccess(Action<TValue>) | Alias for Tap |
OnFailure(Action<TError>) | Executes action on failure, returns same result |
Error Recovery
Section titled “Error Recovery”| Method | Description |
|---|---|
OrElse(Func<TError, Result<TValue, TError>>) | Provides fallback Result on failure |
Recover(Func<TError, TValue>) | Recovers with value on failure |
Deconstruction
Section titled “Deconstruction”var (isSuccess, value, error) = result;Implicit Conversions
Section titled “Implicit Conversions”Result<User, NotFoundError> result = user; // From valueResult<User, NotFoundError> result = notFound; // From errorVoidResult
Section titled “VoidResult”A result type for operations that succeed or fail but don’t return a value.
public readonly struct VoidResult<TError> : IResultBase where TError : IErrorFactory Methods
Section titled “Factory Methods”| Method | Description |
|---|---|
Success() | Creates a successful void result |
Failure(TError error) | Creates a failed void result |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
IsSuccess | bool | True if successful |
IsFailure | bool | True if failed |
Error | TError | The error (throws if success) |
Methods
Section titled “Methods”| Method | Description |
|---|---|
TryGetError(out TError? error) | Returns true and sets error if failed |
Match<T>(onSuccess, onFailure) | Pattern matching |
Tap(Action) | Side effect on success |
OnSuccess(Action) | Alias for Tap |
OnFailure(Action<TError>) | Side effect on failure |
OrElse(Func<TError, VoidResult<TError>>) | Fallback on failure |
Represents an optional value (Some or None). Use when absence is normal, not exceptional.
public readonly struct Maybe<T>Factory Methods
Section titled “Factory Methods”| Method | Description |
|---|---|
Some(T value) | Creates a Maybe with a value |
None() | Creates an empty Maybe |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
HasValue | bool | True if has a value |
Value | T | The value (throws if None) |
Methods
Section titled “Methods”| Method | Description |
|---|---|
TryGetValue(out T? value) | Safe value access |
GetValueOrDefault(T fallback) | Returns value or fallback |
Match<TResult>(onSome, onNone) | Pattern matching |
Map<TNew>(Func<T, TNew>) | Transform value if present |
Bind<TNew>(Func<T, Maybe<TNew>>) | Chain to another Maybe |
ToResult<TError>(errorFactory) | Convert to Result, None becomes error |
Multi-Error Types
Section titled “Multi-Error Types”Source-generated variants for operations that can fail in multiple ways.
Result<User, NotFoundError, ForbiddenError> GetUser(int id, ClaimsPrincipal user);Result<Order, NotFoundError, ForbiddenError, ValidationError> CreateOrder(OrderRequest request);Supports up to 8 error types. Match requires handlers for all error types:
result.Match( user => Ok(user), notFound => NotFound(), forbidden => Forbid());Async Extensions
Section titled “Async Extensions”All methods support async pipelines with CancellationToken.
Task<Result<T, E>> Extensions
Section titled “Task<Result<T, E>> Extensions”| Method | Description |
|---|---|
MapAsync(mapper, ct) | Transform success value |
MapAsync(asyncMapper, ct) | Transform with async mapper |
BindAsync(binder, ct) | Chain to Result-returning function |
BindAsync(asyncBinder, ct) | Chain to async Result-returning function |
MatchAsync(onSuccess, onFailure, ct) | Pattern matching |
TapAsync(asyncAction, ct) | Async side effect on success |
OnFailureAsync(asyncAction, ct) | Async side effect on failure |
EnsureAsync(asyncPredicate, errorFactory, ct) | Async validation |
OrElseAsync(asyncFallback, ct) | Async fallback on failure |
Result<T, E> to Async
Section titled “Result<T, E> to Async”| Method | Description |
|---|---|
MapAsync(asyncMapper, ct) | Start async pipeline from sync Result |
BindAsync(asyncBinder, ct) | Start async pipeline from sync Result |
TapAsync(asyncAction, ct) | Async side effect |
OnFailureAsync(asyncAction, ct) | Async side effect on failure |
EnsureAsync(asyncPredicate, errorFactory, ct) | Async validation |
OrElseAsync(asyncFallback, ct) | Async fallback |
Task<VoidResult> Extensions
Section titled “Task<VoidResult> Extensions”| Method | Description |
|---|---|
MatchAsync(onSuccess, onFailure, ct) | Pattern matching |
ThenAsync(next, ct) | Chain another void operation |
TapAsync(asyncAction, ct) | Async side effect on success |
OnFailureAsync(asyncAction, ct) | Async side effect on failure |
OrElseAsync(asyncFallback, ct) | Async fallback |
Aggregation Extensions
Section titled “Aggregation Extensions”Combine (Fail-Fast)
Section titled “Combine (Fail-Fast)”Combines multiple results. Fails immediately on first error.
// Combine 2 resultsvar combined = Result.Combine(result1, result2); // Result<(T1, T2), TError>
// Combine 3 resultsvar combined = Result.Combine(result1, result2, result3); // Result<(T1, T2, T3), TError>
// Up to 5 results supportedCollectAll (Error Accumulation)
Section titled “CollectAll (Error Accumulation)”Collects all errors instead of stopping at first.
var results = new[] { result1, result2, result3 };var collected = results.CollectAll(); // Result<TValue[], AggregateError<TError>>
// Access all errorsif (collected.TryGetError(out var aggregate)){ foreach (var error in aggregate.Errors) Console.WriteLine(error.Code);}HTTP Error Types
Section titled “HTTP Error Types”Built-in error types with HTTP semantics.
Common Properties
Section titled “Common Properties”All HTTP errors implement IHttpError:
public interface IHttpError : IError{ int StatusCode { get; } string? Title { get; }}NotFoundError (404)
Section titled “NotFoundError (404)”NotFoundError.Create("User", userId);NotFoundError.Create("Order", orderId, "Order was deleted");
// Propertieserror.EntityType // "User"error.EntityId // "42"error.Detail // Optional detail messageUnauthorizedError (401)
Section titled “UnauthorizedError (401)”UnauthorizedError.InvalidCredentials();UnauthorizedError.TokenExpired();UnauthorizedError.Create("Custom reason");ForbiddenError (403)
Section titled “ForbiddenError (403)”ForbiddenError.Create("admin/users", "delete");new ForbiddenError { Resource = "settings", Operation = "write" };ConflictError (409)
Section titled “ConflictError (409)”ConflictError.AlreadyExists("User", email);ConflictError.ConcurrencyConflict("Order");
// Propertieserror.EntityType // "User"error.EntityId // "user@example.com"BadRequestError (400)
Section titled “BadRequestError (400)”BadRequestError.Create("Invalid date format");BadRequestError.Create("Invalid value", "startDate");
// Propertieserror.Reason // "Invalid date format"error.ParameterName // "startDate" (optional)InternalServerError (500)
Section titled “InternalServerError (500)”InternalServerError.Create("Database connection failed");InternalServerError.FromException(ex);
// Implements IDiagnosticError for exception detailserror.ExceptionType // "SqlException"error.ExceptionMessage // "Connection timeout"ASP.NET Core Integration
Section titled “ASP.NET Core Integration”Service Registration
Section titled “Service Registration”// Basic registrationbuilder.Services.AddPragmaticResult();
// With custom message resolverbuilder.Services.AddPragmaticResult<LocalizedErrorResolver>();ResultEndpointFilter (Minimal APIs)
Section titled “ResultEndpointFilter (Minimal APIs)”// Apply to endpoint groupapp.MapGroup("api").WithResultHandling();
// Skip for specific endpointapp.MapGet("/raw", [SkipResultHandling] () => GetResult());ResultActionFilter (Controllers)
Section titled “ResultActionFilter (Controllers)”// Global registrationbuilder.Services.AddControllers(opt => opt.Filters.Add<ResultActionFilter>());
// Skip for specific action[SkipResultHandling]public async Task<Result<User, NotFoundError>> GetRaw(int id) => ...;Manual Conversion Extensions
Section titled “Manual Conversion Extensions”// IResult (Minimal API)result.ToHttpResult(factory); // 200 or ProblemDetailsresult.ToHttpResult(factory, 201); // Custom success statusresult.ToCreatedResult(factory, "/users/42"); // 201 with Locationresult.ToNoContentResult(factory); // 204 or ProblemDetails
// IActionResult (Controllers)result.ToActionResult(factory);result.ToActionResult(factory, 201);result.ToCreatedAtActionResult(factory, "Get", new { id });JSON Serialization
Section titled “JSON Serialization”Registration
Section titled “Registration”// For Minimal APIsbuilder.Services.ConfigureHttpJsonOptions(opt => opt.SerializerOptions.Converters.Add(new ResultJsonConverterFactory()));
// For Controllersbuilder.Services.AddControllers() .AddJsonOptions(opt => opt.JsonSerializerOptions.Converters.Add(new ResultJsonConverterFactory()));JSON Format
Section titled “JSON Format”// Success{ "isSuccess": true, "value": { "id": 42, "name": "John" }}
// Failure{ "isSuccess": false, "error": { "code": "NOT_FOUND", "entityType": "User", "entityId": "42" }}OpenAPI / Swagger
Section titled “OpenAPI / Swagger”Schema Transformer
Section titled “Schema Transformer”Automatically generates correct schemas for Result types.
builder.Services.AddOpenApi(opt =>{ opt.AddSchemaTransformer<ResultSchemaTransformer>();});Transforms Result<User, NotFoundError> endpoints to show:
- 200 OK with User schema
- 404 Not Found with ProblemDetails schema
Interfaces
Section titled “Interfaces”IError
Section titled “IError”Base interface for all error types.
public interface IError{ string Code { get; } // Semantic code like "NOT_FOUND"}IHttpError
Section titled “IHttpError”Extends IError with HTTP semantics.
public interface IHttpError : IError{ int StatusCode { get; } string? Title { get; }}IDiagnosticError
Section titled “IDiagnosticError”For errors with diagnostic information (exceptions).
public interface IDiagnosticError{ string? ExceptionType { get; } string? ExceptionMessage { get; } string? StackTrace { get; }}IResultBase
Section titled “IResultBase”Marker interface for Result type identification at runtime.
public interface IResultBase{ bool IsSuccess { get; } bool IsFailure { get; }}IErrorMessageResolver
Section titled “IErrorMessageResolver”For custom error message resolution (localization).
public interface IErrorMessageResolver{ string? GetMessage(IError error);}AggregateError
Section titled “AggregateError”Container for multiple errors from CollectAll operations.
public readonly struct AggregateError<TError> : IError where TError : IError{ public string Code => "AGGREGATE_ERROR"; public IReadOnlyList<TError> Errors { get; } public int Count { get; }}