From a9211ba23aef5e4038e28df162b5a0494317b2d4 Mon Sep 17 00:00:00 2001 From: David Berry Date: Thu, 23 Oct 2025 23:18:08 -0500 Subject: [PATCH] Added BusinessRuleViolationError class and updated mapping functions in ApiControllerBase --- .../Controllers/ApiControllerBaseTests.cs | 50 +++++++++++++++++++ .../Controllers/ApiControllerBase.cs | 4 ++ .../Functional/BusinessRuleViolationError.cs | 19 +++++++ 3 files changed, 73 insertions(+) create mode 100644 DavidBerry.Framework/DavidBerry.Framework/Functional/BusinessRuleViolationError.cs diff --git a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ApiControllerBaseTests.cs b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ApiControllerBaseTests.cs index c4fd10d..e62ed5a 100644 --- a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ApiControllerBaseTests.cs +++ b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ApiControllerBaseTests.cs @@ -44,6 +44,30 @@ public void MapErrorResult_ReturnsBadRequest_WhenInvalidDataErrorInResult() } + [Fact] + public void MapErrorResult_ReturnsUnprocessableContent_WhenBusinessRuleViolationErrorInResult() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new BusinessRuleViolationError("That is not allowed!")); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var badRequestResult = actionResult as UnprocessableEntityObjectResult; + badRequestResult.Value.ShouldBeOfType(); + + var apiMessageModel = badRequestResult.Value as ApiMessageModel; + apiMessageModel.Message.ShouldBe("That is not allowed!"); + } + + [Fact] public void MapErrorResult_ReturnsObjectNotFound_WhenObjectNotFoundErrorInResult() @@ -149,6 +173,32 @@ public void MapErrorResult_ReturnsBadRequest_WhenResultIsFailure_WithInvalidData } + + [Fact] + public void MapErrorResult_ReturnsUnprocessableEntity_WhenResultIsFailure_WithBusinessRuleViolationError() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new BusinessRuleViolationError("That is not allowed")); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var badRequestResult = actionResult as UnprocessableEntityObjectResult; + badRequestResult.Value.ShouldBeOfType(); + + var apiMessageModel = badRequestResult.Value as ApiMessageModel; + apiMessageModel.Message.ShouldBe("That is not allowed"); + + } + + [Fact] public void MapErrorResult_ReturnsNotFound_WhenResultIsFailure_WithObjectNotFoundError() { diff --git a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs index 7d59b9e..76ed527 100644 --- a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs +++ b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs @@ -115,6 +115,8 @@ protected internal ActionResult MapErrorResult(Result result) { case InvalidDataError error: return BadRequest(new ApiMessageModel() { Message = error.Message }); + case BusinessRuleViolationError error: + return UnprocessableEntity(new ApiMessageModel() { Message = error.Message }); case ObjectNotFoundError error: return NotFound(new ApiMessageModel() { Message = error.Message }); case ObjectAlreadyExistsError error: @@ -132,6 +134,8 @@ protected internal ActionResult MapErrorResult(Result result) { case InvalidDataError e: return BadRequest(new ApiMessageModel() { Message = e.Message }); + case BusinessRuleViolationError error: + return UnprocessableEntity(new ApiMessageModel() { Message = error.Message }); case ObjectNotFoundError e: return NotFound(new ApiMessageModel() { Message = e.Message }); default: diff --git a/DavidBerry.Framework/DavidBerry.Framework/Functional/BusinessRuleViolationError.cs b/DavidBerry.Framework/DavidBerry.Framework/Functional/BusinessRuleViolationError.cs new file mode 100644 index 0000000..0bb3eb2 --- /dev/null +++ b/DavidBerry.Framework/DavidBerry.Framework/Functional/BusinessRuleViolationError.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DavidBerry.Framework.Functional +{ + /// + /// Represents an error where a business rule has been violated + /// + public class BusinessRuleViolationError : Error + { + + public BusinessRuleViolationError(string message) : base(message) + { + } + } +}