From 2e91ca558c138670086866cbdc0577b355eca44f Mon Sep 17 00:00:00 2001 From: Havunen Date: Wed, 21 Feb 2024 22:55:50 +0200 Subject: [PATCH] Adds support for RequestBodyFilters and ParameterFilters when constructing schema from Metadata fixes https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2613 and https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2561 --- .../SwaggerGenerator/SwaggerGenerator.cs | 35 +++++- .../SwaggerGenerator/SwaggerGeneratorTests.cs | 103 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs b/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs index d8f29accf6..08864f0282 100644 --- a/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs +++ b/src/DotSwashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs @@ -282,6 +282,18 @@ private OpenApiOperation GenerateOpenApiOperationFromMetadata(ApiDescription api apiParameter.PropertyInfo(), apiParameter.ParameterInfo(), apiParameter.RouteInfo); + + var filterContext = new ParameterFilterContext( + apiParameter, + _schemaGenerator, + schemaRepository, + apiParameter.PropertyInfo(), + apiParameter.ParameterInfo()); + + foreach (var filter in _options.ParameterFilters) + { + filter.Apply(parameter, filterContext); + } } } @@ -290,6 +302,7 @@ private OpenApiOperation GenerateOpenApiOperationFromMetadata(ApiDescription api { foreach (var content in requestContentTypes) { + RequestBodyFilterContext filterContext = null; var fromBodyParam = apiDescription.ParameterDescriptions.SingleOrDefault(desc => desc.IsFromBody()); if (fromBodyParam is not null) { @@ -297,7 +310,15 @@ private OpenApiOperation GenerateOpenApiOperationFromMetadata(ApiDescription api fromBodyParam.Type, schemaRepository, fromBodyParam.PropertyInfo(), - fromBodyParam.ParameterInfo()); + fromBodyParam.ParameterInfo() + ); + + filterContext = new RequestBodyFilterContext( + bodyParameterDescription: fromBodyParam, + formParameterDescriptions: null, + schemaGenerator: _schemaGenerator, + schemaRepository: schemaRepository + ); } else { @@ -313,9 +334,21 @@ private OpenApiOperation GenerateOpenApiOperationFromMetadata(ApiDescription api entry => entry.Key, entry => new OpenApiEncoding { Style = ParameterStyle.Form } ); + filterContext = new RequestBodyFilterContext( + bodyParameterDescription: null, + formParameterDescriptions: fromFormParam, + schemaGenerator: _schemaGenerator, + schemaRepository: schemaRepository); } } + if (filterContext != null) + { + foreach (var filter in _options.RequestBodyFilters) + { + filter.Apply(operation.RequestBody, filterContext); + } + } } } diff --git a/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs b/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs index d1fbd025b3..4636ace24c 100644 --- a/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs +++ b/test/DotSwashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs @@ -1330,6 +1330,56 @@ public void GetSwagger_SupportsOption_ParameterFilters() Assert.Equal("v1", ((OpenApiString)operation.Parameters[0].Extensions["X-docName"]).Value); } + [Fact] + public void GetSwagger_SupportsOption_ParameterFilters_WithMetaData() + { + var apiDesc = ApiDescriptionFactory.Create( + c => nameof(c.ActionWithParameter), + groupName: "v1", + httpMethod: "POST", + relativePath: "resource", + parameterDescriptions: new[] + { + new ApiParameterDescription { Name = "param", Source = BindingSource.Query } + }); + apiDesc.ActionDescriptor.EndpointMetadata = new List() + { + new OpenApiOperation + { + Parameters = new List() { + new OpenApiParameter + { + Name = "param", + Content = new Dictionary + { + } + } + } + } + }; + var subject = Subject( + apiDescriptions: new[] { apiDesc }, + options: Options.Create(new SwaggerGeneratorOptions + { + SwaggerDocs = new Dictionary(StringComparer.Ordinal) + { + ["v1"] = new OpenApiInfo { Version = "V1", Title = "Test API" } + }, + ParameterFilters = new List + { + new TestParameterFilter() + } + }) + ); + + var document = subject.GetSwagger("v1"); + + var operation = document.Paths["/resource"].Operations[OperationType.Post]; + Assert.Equal(2, operation.Parameters[0].Extensions.Count()); + Assert.Equal("bar", ((OpenApiString)operation.Parameters[0].Extensions["X-foo"]).Value); + Assert.Equal("v1", ((OpenApiString)operation.Parameters[0].Extensions["X-docName"]).Value); + } + [Fact] public void GetSwagger_SupportsOption_RequestBodyFilters() { @@ -1367,6 +1417,59 @@ public void GetSwagger_SupportsOption_RequestBodyFilters() Assert.Equal("v1", ((OpenApiString)operation.RequestBody.Extensions["X-docName"]).Value); } + [Fact] + public void GetSwagger_SupportsOption_RequestBodyFilters_WithMetaData() + { + var apiDesc = ApiDescriptionFactory.Create( + c => nameof(c.ActionWithParameter), + groupName: "v1", + httpMethod: "POST", + relativePath: "resource", + parameterDescriptions: new[] + { + new ApiParameterDescription { Name = "param", Source = BindingSource.Body } + }); + apiDesc.ActionDescriptor.EndpointMetadata = new List() + { + new OpenApiOperation + { + RequestBody = new OpenApiRequestBody + { + Content = new Dictionary + { + ["multipart/form-data"] = new OpenApiMediaType + { + // These values are null + Schema = null, + Encoding = null + } + } + } + } + }; + var subject = Subject( + apiDescriptions: new[] { apiDesc }, + options: Options.Create(new SwaggerGeneratorOptions + { + SwaggerDocs = new Dictionary(StringComparer.Ordinal) + { + ["v1"] = new OpenApiInfo { Version = "V1", Title = "Test API" } + }, + RequestBodyFilters = new List + { + new TestRequestBodyFilter() + } + }) + ); + + var document = subject.GetSwagger("v1"); + + var operation = document.Paths["/resource"].Operations[OperationType.Post]; + Assert.Equal(2, operation.RequestBody.Extensions.Count); + Assert.Equal("bar", ((OpenApiString)operation.RequestBody.Extensions["X-foo"]).Value); + Assert.Equal("v1", ((OpenApiString)operation.RequestBody.Extensions["X-docName"]).Value); + } + [Fact] public void GetSwagger_SupportsOption_OperationFilters() {