From 70a87fe15f01436ddd4cab36c2571ae4c91856ec Mon Sep 17 00:00:00 2001 From: Matt Frear Date: Sun, 19 Apr 2020 21:23:21 +1200 Subject: [PATCH 1/3] Add examples for parameters using new example attribute --- .gitignore | 3 +- README.md | 3 +- .../XmlComments/XmlCommentsSchemaFilter.cs | 6 +++ .../Fixtures/FakeControllerWithXmlComments.cs | 26 ++++++++++++- ...Swashbuckle.AspNetCore.SwaggerGen.Test.xml | 11 ++++++ .../XmlCommentsSchemaFilterTests.cs | 37 ++++++++++++++++++- .../Controllers/CrudActionsController.cs | 12 +++--- 7 files changed, 88 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 4c3b230aa5..2ecf6da877 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ artifacts/ .DS_Store Thumbs.db test/WebSites/CliExample/wwwroot/api-docs/v1/*.json -test/WebSites/CliExampleWithFactory/wwwroot/api-docs/v1/*.json \ No newline at end of file +test/WebSites/CliExampleWithFactory/wwwroot/api-docs/v1/*.json +*ncrunch* \ No newline at end of file diff --git a/README.md b/README.md index c07025606f..f458a5d16b 100644 --- a/README.md +++ b/README.md @@ -460,12 +460,13 @@ To enhance the generated docs with human-friendly descriptions, you can annotate } ``` -3. Annotate your actions with summary, remarks and response tags: +3. Annotate your actions with summary, param, remarks and response tags: ```csharp /// /// Retrieves a specific product by unique id /// + /// /// Awesomeness! /// Product created /// Product has missing/invalid values diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs index 58702ec7f4..f89c94119c 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs @@ -80,6 +80,12 @@ private void ApplyParamTags(OpenApiSchema schema, ParameterInfo parameterInfo) if (paramNode != null) { schema.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml); + + var example = paramNode.GetAttribute("example", ""); + if (!string.IsNullOrEmpty(example)) + { + schema.Example = ConvertToOpenApiType(parameterInfo.ParameterType, schema, example); + } } } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs index fa666c2265..4e2aafdc1a 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/FakeControllerWithXmlComments.cs @@ -1,4 +1,7 @@ -namespace Swashbuckle.AspNetCore.SwaggerGen.Test +using Swashbuckle.AspNetCore.TestSupport; +using System; + +namespace Swashbuckle.AspNetCore.SwaggerGen.Test { /// /// Summary for FakeControllerWithXmlComments @@ -24,5 +27,26 @@ public void ActionWithParamTags(string param1, string param2) /// Description for 400 response public void ActionWithResponseTags() { } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void ActionWithExampleParams( + bool boolParam, + int intParam, + long longParam, + float floatParam, + double doubleParam, + IntEnum enumParam, + Guid guidParam, + string stringParam, + int badExampleIntParam) + { } } } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml index 3cdad65b6b..c1cf70e6e1 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.xml @@ -43,6 +43,17 @@ Description for 200 response Description for 400 response + + + + + + + + + + + Summary for XmlAnnotatedGenericType diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs index d1a6c63858..927eb5f164 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs @@ -4,7 +4,6 @@ using System.IO; using Microsoft.OpenApi.Models; using Xunit; -using Swashbuckle.AspNetCore.TestSupport; namespace Swashbuckle.AspNetCore.SwaggerGen.Test { @@ -70,6 +69,42 @@ public void Apply_SetsDescription_FromActionParamTag() Assert.Equal("Description for param1", schema.Description); } + [Theory] + [InlineData(0, "boolean", null, true)] + [InlineData(1, "integer", "int32", 27)] + [InlineData(2, "integer", "int64", 4294967296L)] + [InlineData(3, "number", "float", 1.23F)] + [InlineData(4, "number", "double", 1.25D)] + [InlineData(5, "integer", "int32", 2)] + [InlineData(6, "string", "uuid", "1edab3d2-311a-4782-9ec9-a70d0478b82f")] + [InlineData(7, "string", null, "Example for StringProperty")] + [InlineData(8, "integer", "int32", null)] + public void Apply_SetsExample_FromActionParamTag( + int parameterIndex, + string schemaType, + string schemaFormat, + object expectedValue) + { + var schema = new OpenApiSchema { Type = schemaType, Format = schemaFormat }; + + var parameterInfo = typeof(FakeControllerWithXmlComments) + .GetMethod(nameof(FakeControllerWithXmlComments.ActionWithExampleParams)) + .GetParameters()[parameterIndex]; + var filterContext = new SchemaFilterContext(parameterInfo.ParameterType, null, null, parameterInfo: parameterInfo); + + Subject().Apply(schema, filterContext); + + if (expectedValue != null) + { + Assert.NotNull(schema.Example); + Assert.Equal(expectedValue, schema.Example.GetType().GetProperty("Value").GetValue(schema.Example)); + } + else + { + Assert.Null(schema.Example); + } + } + [Theory] [InlineData(typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.BoolProperty), "boolean", null, true)] [InlineData(typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.IntProperty), "integer", "int32", 10)] diff --git a/test/WebSites/Basic/Controllers/CrudActionsController.cs b/test/WebSites/Basic/Controllers/CrudActionsController.cs index cd10f75194..b6287ff9cb 100644 --- a/test/WebSites/Basic/Controllers/CrudActionsController.cs +++ b/test/WebSites/Basic/Controllers/CrudActionsController.cs @@ -35,7 +35,7 @@ public Product Create([FromBody, Required]Product product) /// /// Searches the collection of products by description key words /// - /// A list of search terms + /// A list of search terms /// [HttpGet(Name = "SearchProducts")] public IEnumerable Get([FromQuery(Name = "kw")]string keywords = "foobar") @@ -48,9 +48,9 @@ public IEnumerable Get([FromQuery(Name = "kw")]string keywords = "fooba } /// - /// Returns a specific product + /// Returns a specific product /// - /// + /// /// [HttpGet("{id}", Name = "GetProduct")] public Product Get(int id) @@ -61,7 +61,7 @@ public Product Get(int id) /// /// Updates all properties of a specific product /// - /// + /// /// [HttpPut("{id}", Name = "UpdateProduct")] public void Update(int id, [FromBody, Required]Product product) @@ -71,7 +71,7 @@ public void Update(int id, [FromBody, Required]Product product) /// /// Updates some properties of a specific product /// - /// + /// /// [HttpPatch("{id}", Name = "PatchProduct")] public void Patch(int id, [FromBody, Required]IDictionary updates) @@ -81,7 +81,7 @@ public void Patch(int id, [FromBody, Required]IDictionary update /// /// Deletes a specific product /// - /// + /// [HttpDelete("{id}", Name = "DeleteProduct")] public void Delete(int id) { From 6ed0fb983631ff477c401484eb852a4a5738e250 Mon Sep 17 00:00:00 2001 From: Matt Frear Date: Sun, 19 Apr 2020 21:27:12 +1200 Subject: [PATCH 2/3] Add description to example param --- README.md | 2 +- test/WebSites/Basic/Controllers/CrudActionsController.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f458a5d16b..31a0a5d6d7 100644 --- a/README.md +++ b/README.md @@ -466,7 +466,7 @@ To enhance the generated docs with human-friendly descriptions, you can annotate /// /// Retrieves a specific product by unique id /// - /// + /// The product id /// Awesomeness! /// Product created /// Product has missing/invalid values diff --git a/test/WebSites/Basic/Controllers/CrudActionsController.cs b/test/WebSites/Basic/Controllers/CrudActionsController.cs index b6287ff9cb..3e13b7ffdf 100644 --- a/test/WebSites/Basic/Controllers/CrudActionsController.cs +++ b/test/WebSites/Basic/Controllers/CrudActionsController.cs @@ -50,7 +50,7 @@ public IEnumerable Get([FromQuery(Name = "kw")]string keywords = "fooba /// /// Returns a specific product /// - /// + /// The product id /// [HttpGet("{id}", Name = "GetProduct")] public Product Get(int id) From 0c7b8d4815d3607ef78fadd6701fc83dd0eae7e4 Mon Sep 17 00:00:00 2001 From: Matt Frear Date: Sun, 19 Apr 2020 21:34:29 +1200 Subject: [PATCH 3/3] Reorder param --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 31a0a5d6d7..452d95acf9 100644 --- a/README.md +++ b/README.md @@ -460,14 +460,14 @@ To enhance the generated docs with human-friendly descriptions, you can annotate } ``` -3. Annotate your actions with summary, param, remarks and response tags: +3. Annotate your actions with summary, remarks, param and response tags: ```csharp /// /// Retrieves a specific product by unique id /// - /// The product id /// Awesomeness! + /// The product id /// Product created /// Product has missing/invalid values /// Oops! Can't create your product right now