Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using Alba;
using IntegrationTests;
using Marten;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Shouldly;
using Wolverine.Marten;
using Wolverine.Persistence;
using WolverineWebApi.Todos;
using Xunit.Abstractions;

namespace Wolverine.Http.Tests.Persistence;

public class RequiredTodoAttributeEndpoint {

public static async Task<(Todo2?, ProblemDetails)> LoadAsync(string id, IDocumentSession session)
{
var todo = await session.LoadAsync<Todo2>(id);
return (todo, todo != null ? WolverineContinue.NoProblems : new ProblemDetails { Detail = "Todo not found by id", Status = StatusCodes.Status404NotFound } );
}
// Should 404 w/ ProblemDetails on missing
[WolverineGet("/required/todo404required/{id}")]
public static Todo2 GetWithAttribute([Required] Todo2 todo)
=> todo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Alba;
using IntegrationTests;
using Marten;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Shouldly;
using Wolverine;
using Wolverine.Http;
using Wolverine.Marten;
using Xunit.Abstractions;

public class reacting_to_required_attribute : IAsyncLifetime
{
private readonly ITestOutputHelper _output;
private IAlbaHost theHost;

public reacting_to_required_attribute(ITestOutputHelper output)
{
_output = output;
}

public async Task InitializeAsync()
{
var builder = WebApplication.CreateBuilder([]);

// config
builder.Services.AddMarten(opts =>
{
// Establish the connection string to your Marten database
opts.Connection(Servers.PostgresConnectionString);
opts.DatabaseSchemaName = "onmissing";
}).IntegrateWithWolverine().UseLightweightSessions();

builder.Host.UseWolverine(opts => opts.Discovery.IncludeAssembly(GetType().Assembly));

builder.Services.AddWolverineHttp();

// This is using Alba, which uses WebApplicationFactory under the covers
theHost = await AlbaHost.For(builder, app =>
{
app.UseDeveloperExceptionPage();
app.MapWolverineEndpoints();
});
}

async Task IAsyncLifetime.DisposeAsync()
{
if (theHost != null) await theHost.StopAsync();
}

[Fact]
public async Task required_attribute_404_behavior_on_missing()
{
var tracked = await theHost.Scenario(x =>
{
x.Get.Url("/required/todo404required/nonexistent");
x.StatusCodeShouldBe(404);
x.ContentTypeShouldBe("application/problem+json");
});

var details = tracked.ReadAsJson<ProblemDetails>();
details.Detail.ShouldBe("Todo not found by id");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using JasperFx.CodeGeneration.Model;
using JasperFx.Core.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Wolverine.Http.Policies;

Expand All @@ -25,17 +26,19 @@ public SetStatusCodeAndReturnIfEntityIsNullFrame(Variable entity)

public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
{
ValueTypeReturnVariable.TupleVariable? problemDetailsVariable = null;
if (_entity?.Creator is MethodCall { ReturnVariable: ValueTypeReturnVariable vrv })
problemDetailsVariable = vrv.Inners.FirstOrDefault(v => v.Inner.VariableType == typeof(ProblemDetails));
writer.WriteComment("404 if this required object is null");
writer.Write($"BLOCK:if ({_entity.Usage} == null)");
if (problemDetailsVariable != null)
writer.WriteComment($"Take no action if {problemDetailsVariable.Inner.Usage}.Status == 404");
writer.Write(
$"BLOCK:if ({_entity.Usage} == null{(problemDetailsVariable == null ? "" : $" && {problemDetailsVariable.Inner.Usage}.Status != 404")})");
writer.Write($"{_httpResponse.Usage}.{nameof(HttpResponse.StatusCode)} = 404;");
if (method.AsyncMode == AsyncMode.ReturnCompletedTask)
{
writer.Write($"return {typeof(Task).FullNameInCode()}.{nameof(Task.CompletedTask)};");
}
else
{
writer.Write("return;");
}

writer.FinishBlock();

Expand Down
Loading