Skip to content

Commit 0173e45

Browse files
committed
let user override the response validation process
1 parent be8eccf commit 0173e45

4 files changed

Lines changed: 42 additions & 15 deletions

File tree

src/OpenAPI.WebApiGenerator/CodeGeneration/OperationGenerator.cs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Net.Http;
44
using Microsoft.CodeAnalysis;
55
using Microsoft.CodeAnalysis.Text;
6+
using OpenAPI.WebApiGenerator.Extensions;
67

78
namespace OpenAPI.WebApiGenerator.CodeGeneration;
89

@@ -27,11 +28,25 @@ internal partial class Operation
2728
internal const string PathTemplate = "{{pathTemplate}}";
2829
internal const string Method = "{{method.Method}}";
2930
30-
{{HandleMethodSignature}};
31+
/// <summary>
32+
/// Should responses be validated?
33+
/// If the response has already been validated, this can be disabled to avoid redundant validation.
34+
/// </summary>
35+
internal bool ValidateResponse { get; init; } = true;
3136
32-
private Func<ImmutableList<ValidationResult>, Response> HandleValidationError { get; } = validationResult =>
37+
{{HandleMethodSignature.Indent(4)}};
38+
39+
/// <summary>
40+
/// Set a custom delegate to handle request validation errors.
41+
/// <exception cref="JsonValidationException"></exception>
42+
/// </summary>
43+
private Func<ImmutableList<ValidationResult>, Response> HandleRequestValidationError { get; } = validationResult =>
3344
{{jsonValidationExceptionGenerator.CreateThrowJsonValidationExceptionInvocation("Request is not valid", "validationResult")}};
3445
46+
/// <summary>
47+
/// Handle a operation.
48+
/// <exception cref="JsonValidationException"></exception>
49+
/// </summary>
3550
internal static async Task HandleAsync(
3651
HttpContext context,
3752
[FromServices] Operation operation,
@@ -45,20 +60,22 @@ internal static async Task HandleAsync(
4560
var validationContext = request.Validate(validationLevel);
4661
if (!validationContext.IsValid)
4762
{
48-
operation.HandleValidationError(validationContext.Results.WithLocation(configuration.OpenApiSpecificationUri))
63+
operation.HandleRequestValidationError(validationContext.Results.WithLocation(configuration.OpenApiSpecificationUri))
4964
.WriteTo(context.Response);
5065
return;
5166
}
5267
5368
var response = await operation.HandleAsync(request, cancellationToken)
5469
.ConfigureAwait(false);
55-
validationContext = response.Validate(validationLevel);
56-
if (!validationContext.IsValid)
70+
if (operation.ValidateResponse)
5771
{
58-
var validationResult = validationContext.Results.WithLocation(configuration.OpenApiSpecificationUri);
59-
{{jsonValidationExceptionGenerator.CreateThrowJsonValidationExceptionInvocation("Response is not valid", "validationResult")}};
72+
validationContext = response.Validate(validationLevel);
73+
if (!validationContext.IsValid)
74+
{
75+
var validationResult = validationContext.Results.WithLocation(configuration.OpenApiSpecificationUri);
76+
{{jsonValidationExceptionGenerator.CreateThrowJsonValidationExceptionInvocation("Response is not valid", "validationResult")}};
77+
}
6078
}
61-
6279
response.WriteTo(context.Response);
6380
}
6481
}
@@ -79,7 +96,12 @@ internal static async Task HandleAsync(
7996
}
8097

8198
private const string HandleMethodSignature =
82-
"internal partial Task<Response> HandleAsync(Request request, CancellationToken cancellationToken)";
99+
"""
100+
/// <summary>
101+
/// Handles a request for this operation.
102+
/// </summary>
103+
internal partial Task<Response> HandleAsync(Request request, CancellationToken cancellationToken)
104+
""";
83105

84106
private static bool HasImplementedHandleMethod(INamedTypeSymbol typeSymbol)
85107
{

tests/Example.OpenApi20/Paths/FooFooId/Put/Operation.Handler.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ internal partial class Operation
77
{
88
public Operation()
99
{
10-
HandleValidationError = HandleValidationErrors;
10+
HandleRequestValidationError = HandleValidationErrors;
11+
ValidateResponse = false;
1112
}
1213

13-
private static Response HandleValidationErrors(ImmutableList<ValidationResult> validationResults)
14+
private static Response.BadRequest400 HandleValidationErrors(ImmutableList<ValidationResult> validationResults)
1415
{
1516
var response = validationResults.Select(result =>
1617
Responses.BadRequest.RequiredErrorAndName.Create(
@@ -34,6 +35,9 @@ internal partial Task<Response> HandleAsync(Request request, CancellationToken c
3435
Status = 2
3536
}
3637
};
37-
return Task.FromResult<Response>(response);
38+
var validationContext = response.Validate(ValidationLevel.Detailed);
39+
return !validationContext.IsValid
40+
? throw new JsonValidationException("Response is not valid", validationContext.Results)
41+
: Task.FromResult<Response>(response);
3842
}
3943
}

tests/Example.OpenApi30/Paths/FooFooId/Put/Operation.Handler.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ internal partial class Operation
77
{
88
public Operation()
99
{
10-
HandleValidationError = HandleValidationErrors;
10+
HandleRequestValidationError = HandleValidationErrors;
11+
ValidateResponse = true;
1112
}
1213

13-
private static Response HandleValidationErrors(ImmutableList<ValidationResult> validationResults)
14+
private static Response.BadRequest400 HandleValidationErrors(ImmutableList<ValidationResult> validationResults)
1415
{
1516
var response = validationResults.Select(result =>
1617
Components.Responses.BadRequest.Content.ApplicationJson.RequiredErrorAndName.Create(

tests/Example.OpenApi31/Paths/FooFooId/Put/Operation.Handler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ internal partial class Operation
77
{
88
public Operation()
99
{
10-
HandleValidationError = HandleValidationErrors;
10+
HandleRequestValidationError = HandleValidationErrors;
1111
}
1212

1313
private static Response.BadRequest400 HandleValidationErrors(ImmutableList<ValidationResult> validationResults)

0 commit comments

Comments
 (0)