Skip to main content

ErrorResultResponse

Namespace: RA.Utilities.Api.Mapper

The ErrorResultResponse is a static helper class that provides a clean, centralized way to map exceptions from the RA.Utilities.Core.Results layer into standardized IResult objects for ASP.NET Core Minimal APIs. It is a key component for creating consistent error responses when using the Result<T> pattern.

🎯 Purpose​

When your application logic returns a Result<T> that is in a Failure state, it contains an Exception object (e.g., NotFoundException, ConflictException). The ErrorResultResponse.Result method inspects this exception and automatically generates the appropriate HTTP error response (404 Not Found, 409 Conflict, etc.) using the standardized response models from RA.Utilities.Api (namespace RA.Utilities.Api.Response).

This allows you to handle all expected business-level failures in a single, declarative line of code within your API endpoints, keeping them clean and free of repetitive error-handling logic.

📦 Supported Exceptions​

The Result(Exception) method uses a switch expression to map each supported exception type to its corresponding response model and HTTP status code:

ExceptionResponse ModelHTTP Status
BadRequestExceptionBadRequestResponse400 Bad Request
UnauthorizedExceptionUnauthorizedResponse401 Unauthorized
PaymentRequiredExceptionPaymentRequiredResponse402 Payment Required
ForbiddenExceptionForbiddenResponse403 Forbidden
NotFoundExceptionNotFoundResponse404 Not Found
ConflictExceptionConflictResponse409 Conflict
UnprocessableExceptionUnprocessableResponse422 Unprocessable Content
TooManyRequestsExceptionTooManyRequestsResponse429 Too Many Requests
ServiceUnavailableExceptionServiceUnavailableResponse503 Service Unavailable
GatewayTimeoutExceptionGatewayTimeoutResponse504 Gateway Timeout
Any other RaBaseExceptionErrorResponse500 Internal Server Error
Any other ExceptionErrorResponse500 Internal Server Error

Any exception that is not one of the known semantic exceptions is treated as an unexpected server error and returns a generic 500 Internal Server Error response, avoiding leakage of sensitive implementation details.

Only BadRequestException, ConflictException, and NotFoundException currently produce a structured Result payload. The other mappings use the (int responseCode, string responseMessage) constructors, which leave result as null and carry the details on the envelope. See ErrorResultMapper.

🚀 How to Use​

The primary use case for ErrorResultResponse is within the Match method of a Result<T> object. The ErrorResultResponse.Result method has the signature Func<Exception, IResult>, which perfectly matches the signature required by the failure delegate of Match.

This allows you to pass the method directly, creating highly readable and maintainable endpoint code.

Example​

Imagine you have a service that retrieves a product and returns a Result<Product>. The result will be a Failure containing a NotFoundException if the product doesn't exist.

In your Minimal API endpoint, you can use ErrorResultResponse.Result to handle this failure case automatically.

1. The Service Layer returning a Result​

// Application/Features/Products/ProductService.cs
using RA.Utilities.Core.Results;
using RA.Utilities.Core.Exceptions;

public class ProductService
{
public Result<Product> GetProductById(int id)
{
// Simulate not finding a product
if (id != 1)
{
// Return a failure Result containing a NotFoundException
return new NotFoundException(nameof(Product), id);
}

// Return a success Result with the product
return new Product { Id = id, Name = "Sample Product" };
}
}

2. The API Endpoint using Match and ErrorResultResponse​

using RA.Utilities.Api.Mapper;

// Api/Features/Products/ProductEndpoints.cs
app.MapGet("/products/{id}", (int id, ProductService service) =>
{
Result<Product> result = service.GetProductById(id);

// The Match method handles both success and failure outcomes.
// The `ErrorResultResponse.Result` method is passed directly to the failure delegate.
return result.Match<IResult>(
success: product => SuccessResult.Ok(product),
failure: ErrorResultResponse.Result
);
});

What Happens​

  • If you request /products/1, the result is a success, and the success delegate is executed, returning a 200 OK with the product data.
  • If you request /products/99, the result is a failure containing a NotFoundException. The failure delegate (ErrorResultResponse.Result) is executed. It inspects the exception, sees it's a NotFoundException, and automatically returns a 404 Not Found with a standardized JSON body:
{
"responseCode": 404,
"responseType": 8,
"responseMessage": "Product with value '99' was not found.",
"result": {
"entity": "Product",
"value": 99,
"errorCode": "Product with value '99' was not found.",
"errorMessage": ""
}
}
Known nested-payload issue

ErrorResultMapper.ToResponse(NotFoundException) currently writes the exception message into NotFoundResult.ErrorCode and leaves ErrorMessage empty. The envelope (responseCode, responseType, responseMessage) is correct. A fix is pending; see Troubleshooting.

The responseType numbers are the default System.Text.Json output. Register JsonStringEnumConverter to write "NotFound" instead; see ResponseType.