From f48b8452d3d6352563ed8b23695eaabd4ad10a67 Mon Sep 17 00:00:00 2001 From: Aaron Po Date: Thu, 12 Feb 2026 01:08:43 -0500 Subject: [PATCH] Update tests --- .../ValidationExceptionHandlingMiddleware.cs | 47 +++++++++++++++++++ src/Core/API/API.Core/Program.cs | 29 +++++++++++- .../API.Specs/Features/Registration.feature | 1 - 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/Core/API/API.Core/Middleware/ValidationExceptionHandlingMiddleware.cs diff --git a/src/Core/API/API.Core/Middleware/ValidationExceptionHandlingMiddleware.cs b/src/Core/API/API.Core/Middleware/ValidationExceptionHandlingMiddleware.cs new file mode 100644 index 0000000..a631cd0 --- /dev/null +++ b/src/Core/API/API.Core/Middleware/ValidationExceptionHandlingMiddleware.cs @@ -0,0 +1,47 @@ +using System.Net; +using System.Text.Json; +using API.Core.Contracts.Common; +using FluentValidation; + +namespace API.Core.Middleware; + +public class ValidationExceptionHandlingMiddleware(RequestDelegate next) +{ + public async Task InvokeAsync(HttpContext context) + { + try + { + await next(context); + } + catch (ValidationException ex) + { + await HandleValidationExceptionAsync(context, ex); + } + } + + private static Task HandleValidationExceptionAsync(HttpContext context, ValidationException exception) + { + context.Response.ContentType = "application/json"; + context.Response.StatusCode = (int)HttpStatusCode.BadRequest; + + var errors = exception.Errors + .Select(e => e.ErrorMessage) + .ToList(); + + var message = errors.Count == 1 + ? errors[0] + : "Validation failed. " + string.Join(" ", errors); + + var response = new ResponseBody + { + Message = message + }; + + var jsonOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + return context.Response.WriteAsync(JsonSerializer.Serialize(response, jsonOptions)); + } +} diff --git a/src/Core/API/API.Core/Program.cs b/src/Core/API/API.Core/Program.cs index 93b762f..b4def9f 100644 --- a/src/Core/API/API.Core/Program.cs +++ b/src/Core/API/API.Core/Program.cs @@ -1,4 +1,6 @@ using FluentValidation; +using FluentValidation.AspNetCore; +using Microsoft.AspNetCore.Mvc; using Repository.Core.Repositories.Auth; using Repository.Core.Repositories.UserAccount; using Repository.Core.Sql; @@ -9,13 +11,35 @@ using Service.Core.User; var builder = WebApplication.CreateBuilder(args); -builder.Services.AddControllers(); +builder.Services.AddControllers() + .ConfigureApiBehaviorOptions(options => + { + options.InvalidModelStateResponseFactory = context => + { + var errors = context.ModelState.Values + .SelectMany(v => v.Errors) + .Select(e => e.ErrorMessage) + .ToList(); + + var message = errors.Count == 1 + ? errors[0] + : string.Join(" ", errors); + + var response = new + { + message + }; + + return new BadRequestObjectResult(response); + }; + }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddOpenApi(); // Add FluentValidation builder.Services.AddValidatorsFromAssemblyContaining(); +builder.Services.AddFluentValidationAutoValidation(); // Add health checks builder.Services.AddHealthChecks(); @@ -59,3 +83,6 @@ lifetime.ApplicationStopping.Register(() => }); app.Run(); + +// Make Program class accessible to test projects +public partial class Program { } diff --git a/src/Core/API/API.Specs/Features/Registration.feature b/src/Core/API/API.Specs/Features/Registration.feature index 6140bea..cf6d3d0 100644 --- a/src/Core/API/API.Specs/Features/Registration.feature +++ b/src/Core/API/API.Specs/Features/Registration.feature @@ -52,7 +52,6 @@ Feature: User Registration | Username | FirstName | LastName | Email | DateOfBirth | Password | | newuser | New | User | newuser@example.com | 1990-01-01 | weakpass | Then the response has HTTP status 400 - And the response JSON should have "message" equal "Password does not meet complexity requirements." Scenario: Cannot register a user younger than 19 years of age (regulatory requirement) Given the API is running