ErrorResultMapper
Namespace: RA.Utilities.Api.Mapper
The ErrorResultMapper is a static helper class responsible for the low-level task of transforming specific exception types from the RA.Utilities.Core.Exceptions package into their corresponding standardized response models from RA.Utilities.Api (namespace RA.Utilities.Api.Response).
🎯 Purpose
The primary purpose of ErrorResultMapper is to centralize the logic for converting exception data into structured DTOs (Data Transfer Objects).
For example, it takes a NotFoundException and creates a
NotFoundResponse object, correctly populating the Entity and Value fields.
This class acts as an internal "factory" for error response bodies.
It is consumed by other helpers, most notably the ErrorResultResponse class, to ensure that all error responses are created consistently.
🔗 Relationship with ErrorResultResponse
While both classes are involved in error handling, they have distinct roles:
ErrorResultMapper: Creates the body of the error response (e.g., aNotFoundResponseobject). It deals with the "what" of the error.ErrorResultResponse: Creates the finalIResultfor the API endpoint. It takes the response body fromErrorResultMapperand wraps it in anIResult(likeResults.Json) with the correct HTTP status code. It deals with the "how" of returning the error.
In general, you will not interact with ErrorResultMapper directly. You will use ErrorResultResponse, which uses this mapper internally.
🚀 How It's Used (Indirectly)
The ErrorResultResponse.Result method is a switch expression that calls the appropriate ErrorResultMapper method based on the exception type.
Here is a simplified view of the code from ErrorResultResponse.cs to illustrate the relationship:
// From RA.Utilities.Api.Mapper.ErrorResultResponse
public static IResult Result(Exception exception) => exception switch
{
// ... other cases
NotFoundException notFoundException => Microsoft.AspNetCore.Http.Results.Json(
ErrorResultMapper.ToResponse(notFoundException), // Creates the response body
statusCode: BaseResponseCode.NotFound
),
// ... other cases
};
As you can see, ErrorResultResponse delegates the creation of the response body to ErrorResultMapper before creating the final Json result.
📦 Available Mappers
The class provides a dedicated mapping method for each custom exception type:
-
ToResponse(BadRequestException ex): Maps aBadRequestExceptionto aBadRequestResponse, converting the exception's validation errors into aBadRequestResultarray. -
ToResponse(ConflictException ex): Maps aConflictExceptionto aConflictResponse, populating theConflictResultwith the entity name and value. -
ToResponse(NotFoundException ex): Maps aNotFoundExceptionto aNotFoundResponse, populating theNotFoundResultwith the entity name and value. -
ToResponse(UnauthorizedException ex): Maps anUnauthorizedExceptionto anUnauthorizedResponse, populating theErrorResultwith the error code and message. -
ToResponse(ForbiddenException ex): Maps aForbiddenExceptionto aForbiddenResponse, populating theErrorResultwith the error code and message. -
ToResponse(PaymentRequiredException ex): Maps aPaymentRequiredExceptionto aPaymentRequiredResponse(HTTP 402), copying the exception's code and message to the envelope and leavingResultasnull. -
ToResponse(UnprocessableException ex): Maps anUnprocessableExceptionto anUnprocessableResponse, populating theErrorResultwith the error code and message. -
ToResponse(TooManyRequestsException ex): Maps aTooManyRequestsExceptionto aTooManyRequestsResponse(HTTP 429), populating theErrorResultwith the error code and message. -
ToResponse(ServiceUnavailableException ex): Maps aServiceUnavailableExceptionto aServiceUnavailableResponse(HTTP 503), populating theErrorResultwith the error code and message. -
ToResponse(GatewayTimeoutException ex): Maps aGatewayTimeoutExceptionto aGatewayTimeoutResponse(HTTP 504), populating theErrorResultwith the error code and message. -
ToResponse(RaBaseException ex): Maps any otherRaBaseExceptionto a genericErrorResponse, using the exception's message and error code.
📦 Response Payload Shapes
The mapper does not populate the same payload for every exception. The table below reflects the current implementation:
| Exception | Response | Result payload |
|---|---|---|
BadRequestException | BadRequestResponse | BadRequestResult[] built from exception.Errors |
ConflictException | ConflictResponse | ConflictResult with Entity, Value, and ErrorMessage |
NotFoundException | NotFoundResponse | NotFoundResult with Entity and Value |
UnauthorizedException | UnauthorizedResponse | null — the envelope carries the code and message |
ForbiddenException | ForbiddenResponse | null — the envelope carries the code and message |
PaymentRequiredException | PaymentRequiredResponse | null — the envelope carries the code and message |
UnprocessableException | UnprocessableResponse | null — the envelope carries the code and message |
TooManyRequestsException | TooManyRequestsResponse | null — the envelope carries the code and message |
ServiceUnavailableException | ServiceUnavailableResponse | null — the envelope carries the code and message |
GatewayTimeoutException | GatewayTimeoutResponse | null — the envelope carries the code and message |
RaBaseException | ErrorResponse | null — the envelope carries the code and message |
NotFoundException payload issueToResponse(NotFoundException) currently passes exception.Message as the third positional argument of NotFoundResult, but that parameter is errorCode, not the message. As a result:
NotFoundResult.EntityandValueare correct.NotFoundResult.ErrorCodecontains the exception message.NotFoundResult.ErrorMessageis"".
The outer NotFoundResponse.ResponseMessage is still correct. A fix is pending; see Troubleshooting.