Skip to content

Commit

Permalink
Add generic variants of ProducesProblem and ProducesValidationProblem
Browse files Browse the repository at this point in the history
  • Loading branch information
captainsafia committed Jul 15, 2024
1 parent 8d9db2f commit fde9f39
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,27 @@ public static RouteHandlerBuilder ProducesProblem(this RouteHandlerBuilder build
return Produces(builder, statusCode, typeof(ProblemDetails), contentType);
}

/// <summary>
/// Adds an <see cref="IProducesResponseTypeMetadata"/> with a <see cref="ProblemDetails"/> type
/// to <see cref="EndpointBuilder.Metadata"/> for all endpoints produced by <paramref name="builder"/>.
/// </summary>
/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
/// <param name="statusCode">The response status code.</param>
/// <param name="contentType">The response content type. Defaults to "application/problem+json".</param>
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
public static TBuilder ProducesProblem<TBuilder>(this TBuilder builder, int statusCode, string? contentType = null)
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
where TBuilder : IEndpointConventionBuilder
{
if (string.IsNullOrEmpty(contentType))
{
contentType = "application/problem+json";
}

return builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(ProblemDetails), [contentType]));
}

/// <summary>
/// Adds an <see cref="IProducesResponseTypeMetadata"/> with a <see cref="HttpValidationProblemDetails"/> type
/// to <see cref="EndpointBuilder.Metadata"/> for all endpoints produced by <paramref name="builder"/>.
Expand All @@ -130,6 +151,30 @@ public static RouteHandlerBuilder ProducesValidationProblem(
return Produces(builder, statusCode, typeof(HttpValidationProblemDetails), contentType);
}

/// <summary>
/// Adds an <see cref="IProducesResponseTypeMetadata"/> with a <see cref="HttpValidationProblemDetails"/> type
/// to <see cref="EndpointBuilder.Metadata"/> for all endpoints produced by <paramref name="builder"/>.
/// </summary>
/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
/// <param name="statusCode">The response status code. Defaults to <see cref="StatusCodes.Status400BadRequest"/>.</param>
/// <param name="contentType">The response content type. Defaults to "application/problem+json".</param>
/// <returns>A <see cref="IEndpointConventionBuilder"/> that can be used to further customize the endpoint.</returns>
#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
public static TBuilder ProducesValidationProblem<TBuilder>(
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
this TBuilder builder,
int statusCode = StatusCodes.Status400BadRequest,
string? contentType = null)
where TBuilder : IEndpointConventionBuilder
{
if (string.IsNullOrEmpty(contentType))
{
contentType = "application/problem+json";
}

return builder.WithMetadata(new ProducesResponseTypeMetadata(statusCode, typeof(HttpValidationProblemDetails), [contentType]));
}

/// <summary>
/// Adds the <see cref="ITagsMetadata"/> to <see cref="EndpointBuilder.Metadata"/> for all endpoints
/// produced by <paramref name="builder"/>.
Expand Down
2 changes: 2 additions & 0 deletions src/Http/Routing/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ Microsoft.AspNetCore.Routing.ContentEncodingMetadata
Microsoft.AspNetCore.Routing.ContentEncodingMetadata.ContentEncodingMetadata(string! value, double quality) -> void
Microsoft.AspNetCore.Routing.ContentEncodingMetadata.Quality.get -> double
Microsoft.AspNetCore.Routing.ContentEncodingMetadata.Value.get -> string!
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.ProducesProblem<TBuilder>(this TBuilder builder, int statusCode, string? contentType = null) -> TBuilder
static Microsoft.AspNetCore.Http.OpenApiRouteHandlerBuilderExtensions.ProducesValidationProblem<TBuilder>(this TBuilder builder, int statusCode = 400, string? contentType = null) -> TBuilder
static Microsoft.AspNetCore.Routing.RouteHandlerServices.Map(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! endpoints, string! pattern, System.Delegate! handler, System.Collections.Generic.IEnumerable<string!>? httpMethods, System.Func<System.Reflection.MethodInfo!, Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions?, Microsoft.AspNetCore.Http.RequestDelegateMetadataResult!>! populateMetadata, System.Func<System.Delegate!, Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions!, Microsoft.AspNetCore.Http.RequestDelegateMetadataResult?, Microsoft.AspNetCore.Http.RequestDelegateResult!>! createRequestDelegate, System.Reflection.MethodInfo! methodInfo) -> Microsoft.AspNetCore.Builder.RouteHandlerBuilder!
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,38 @@ public void Produces_AddsProducesResponseTypeMetadataWithVoidType()
}

[Fact]
public void ProdcesProblem_AddsProducesResponseTypeMetadataWithProblemDetailsType()
public void ProducesProblem_AddsProducesResponseTypeMetadataWithProblemDetailsType()
{
var testBuilder = new TestEndointConventionBuilder();
var builder = new RouteHandlerBuilder(new[] { testBuilder });
static void GenericProducesProblem(IEndpointConventionBuilder builder) => builder.ProducesProblem(StatusCodes.Status400BadRequest);
static void SpecificProducesProblem(RouteHandlerBuilder builder) => builder.ProducesProblem(StatusCodes.Status400BadRequest);

builder.ProducesProblem(StatusCodes.Status400BadRequest);
static void AssertMetadata(EndpointBuilder builder)
{
var metadata = Assert.IsType<ProducesResponseTypeMetadata>(Assert.Single(builder.Metadata));
Assert.Equal(typeof(ProblemDetails), metadata.Type);
Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode);
Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes));
}

RunWithBothBuilders(GenericProducesProblem, SpecificProducesProblem, AssertMetadata);

var metadata = Assert.IsType<ProducesResponseTypeMetadata>(Assert.Single(testBuilder.Metadata));
Assert.Equal(typeof(ProblemDetails), metadata.Type);
Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode);
Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes));
}

[Fact]
public void ProdcesValidiationProblem_AddsProducesResponseTypeMetadataWithHttpValidationProblemDetailsType()
public void ProducesValidationProblem_AddsProducesResponseTypeMetadataWithHttpValidationProblemDetailsType()
{
var testBuilder = new TestEndointConventionBuilder();
var builder = new RouteHandlerBuilder(new[] { testBuilder });
static void GenericProducesProblem(IEndpointConventionBuilder builder) => builder.ProducesValidationProblem();
static void SpecificProducesProblem(RouteHandlerBuilder builder) => builder.ProducesValidationProblem();

builder.ProducesValidationProblem();
static void AssertMetadata(EndpointBuilder builder)
{
var metadata = Assert.IsType<ProducesResponseTypeMetadata>(Assert.Single(builder.Metadata));
Assert.Equal(typeof(HttpValidationProblemDetails), metadata.Type);
Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode);
Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes));
}

var metadata = Assert.IsType<ProducesResponseTypeMetadata>(Assert.Single(testBuilder.Metadata));
Assert.Equal(typeof(HttpValidationProblemDetails), metadata.Type);
Assert.Equal(StatusCodes.Status400BadRequest, metadata.StatusCode);
Assert.Equal("application/problem+json", Assert.Single(metadata.ContentTypes));
RunWithBothBuilders(GenericProducesProblem, SpecificProducesProblem, AssertMetadata);
}

[Fact]
Expand Down

0 comments on commit fde9f39

Please sign in to comment.