From 9cd27e213b4c9f46c833c1b31ae1234616877021 Mon Sep 17 00:00:00 2001
From: "cubecraft-agents[bot]"
<3458173+cubecraft-agents[bot]@users.noreply.github.com>
Date: Sun, 26 Apr 2026 13:26:26 +0000
Subject: [PATCH] CUB-30: Implement PUT /filaments/{id} update endpoint
- Add FluentValidation validators for CreateFilamentRequest and UpdateFilamentRequest
with comprehensive validation rules (required fields, string lengths, hex color format,
weight constraints including WeightRemainingGrams <= WeightTotalGrams, purchase price range)
- Add FluentValidationFilter action filter that auto-runs FluentValidation validators
for all API controller actions before execution, returning 400 with structured error details
- Register FluentValidationFilter in DI and add it to MVC controller filters in Program.cs
- PUT endpoint was already implemented in FilamentsController with proper validation,
404 handling, FK existence checks, serial uniqueness check, and weight constraint check
- This change ensures FluentValidation rules are enforced consistently via the pipeline
---
backend/API/Filters/FluentValidationFilter.cs | 69 +++++++++++
backend/API/Validators/FilamentValidators.cs | 108 ++++++++++++++++++
backend/Program.cs | 10 +-
3 files changed, 186 insertions(+), 1 deletion(-)
create mode 100644 backend/API/Filters/FluentValidationFilter.cs
create mode 100644 backend/API/Validators/FilamentValidators.cs
diff --git a/backend/API/Filters/FluentValidationFilter.cs b/backend/API/Filters/FluentValidationFilter.cs
new file mode 100644
index 0000000..58d89f0
--- /dev/null
+++ b/backend/API/Filters/FluentValidationFilter.cs
@@ -0,0 +1,69 @@
+using FluentValidation;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+
+namespace Extrudex.API.Filters;
+
+///
+/// Action filter that automatically validates request DTOs using FluentValidation
+/// validators registered in DI. Runs before the controller action executes.
+/// Returns 400 Bad Request with validation errors if validation fails.
+///
+public class FluentValidationFilter : IAsyncActionFilter
+{
+ private readonly IServiceProvider _serviceProvider;
+ private readonly ILogger _logger;
+
+ public FluentValidationFilter(IServiceProvider serviceProvider, ILogger logger)
+ {
+ _serviceProvider = serviceProvider;
+ _logger = logger;
+ }
+
+ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+ {
+ foreach (var argument in context.ActionArguments.Values)
+ {
+ if (argument is null) continue;
+
+ var argumentType = argument.GetType();
+ var validatorType = typeof(IValidator<>).MakeGenericType(argumentType);
+
+ // Try to resolve a validator for this argument type
+ var validator = _serviceProvider.GetService(validatorType) as IValidator;
+ if (validator is null) continue;
+
+ _logger.LogDebug("Validating {Type} with {Validator}", argumentType.Name, validator.GetType().Name);
+
+ var validationResult = await validator.ValidateAsync(
+ new ValidationContext