From 850b8468c6c17f84d2ade470d3589941a2f1301d Mon Sep 17 00:00:00 2001 From: Lodewijk Sioen Date: Tue, 17 Jun 2025 10:43:43 +0200 Subject: [PATCH] Allow RequiredAttribute in Middleware See GH-1500 --- .../todo_endpoint_specs.cs | 10 ++++++ .../Policies/RequiredEntityPolicy.cs | 5 +-- .../WolverineWebApi/Samples/TodoController.cs | 32 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs b/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs index 7ad0f663d..3101bc73b 100644 --- a/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs +++ b/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs @@ -58,4 +58,14 @@ await Scenario(opts => opts.StatusCodeShouldBe(404); }); } + + [Fact] + public async Task get_an_automatic_404_when_related_entity_does_not_exist_with_validation() + { + await Scenario(opts => + { + opts.Put.Json(new UpdateRequest("Second", true)).ToUrl("/todos3/1222222222"); + opts.StatusCodeShouldBe(404); + }); + } } \ No newline at end of file diff --git a/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs b/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs index 27c0924a0..27c632c05 100644 --- a/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs +++ b/src/Http/Wolverine.Http/Policies/RequiredEntityPolicy.cs @@ -23,8 +23,9 @@ public void Apply(IReadOnlyList chains, GenerationRules rules, IServi foreach (var parameter in requiredParameters) { - var frame = new SetStatusCodeAndReturnIfEntityIsNullFrame(parameter.ParameterType); - chain.Middleware.Add(frame); + var loadFrame = chain.Middleware.First(m => m.Creates.Any(x => x.VariableType == parameter.ParameterType)); + var stopFrame = new SetStatusCodeAndReturnIfEntityIsNullFrame(parameter.ParameterType); + chain.Middleware.Insert(chain.Middleware.IndexOf(loadFrame) + 1, stopFrame); } } } diff --git a/src/Http/WolverineWebApi/Samples/TodoController.cs b/src/Http/WolverineWebApi/Samples/TodoController.cs index 5051b14b3..bdf7150a4 100644 --- a/src/Http/WolverineWebApi/Samples/TodoController.cs +++ b/src/Http/WolverineWebApi/Samples/TodoController.cs @@ -169,3 +169,35 @@ public static Todo Put(int id, UpdateRequest request, Todo todo, IDocumentSessio return todo; } } + +public static class UpdateEndpoint3 +{ + // Find required Todo entity for the route handler below + public static Task LoadAsync(int id, IDocumentSession session) + => session.LoadAsync(id); + + public static IResult Validate([Required] Todo? todo) + { + return todo.IsComplete + ? Results.ValidationProblem([new("IsComplere", ["Completed Todo cannot be updated"])]) + : WolverineContinue.Result(); + } + + [WolverinePut("/todos3/{id:int}")] + public static StoreDoc Put( + // Route argument + int id, + + // The request body + UpdateRequest request, + + // Entity loaded by the method above, + // but note the [Required] attribute + [Required] Todo? todo) + { + todo.Name = request.Name; + todo.IsComplete = request.IsComplete; + + return MartenOps.Store(todo); + } +}