diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 4751c4b28..3816fb14f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections.Generic; +using System.Linq; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -76,7 +77,7 @@ public void SerializeAsV3(IOpenApiWriter writer) writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, e) => w.WriteAny(e)); // examples - writer.WriteOptionalMap(OpenApiConstants.Examples, Examples, (w, e) => e.SerializeAsV3(w)); + SerializeExamples(writer, Examples); // encoding writer.WriteOptionalMap(OpenApiConstants.Encoding, Encoding, (w, e) => e.SerializeAsV3(w)); @@ -94,5 +95,33 @@ public void SerializeAsV2(IOpenApiWriter writer) { // Media type does not exist in V2. } + + private static void SerializeExamples(IOpenApiWriter writer, IDictionary examples) + { + /* Special case for writing out empty arrays as valid response examples + * Check if there is any example with an empty array as its value and set the flag `hasEmptyArray` to true + * */ + var hasEmptyArray = examples.Values.Any( static example => + example.Value is OpenApiArray arr && arr.Count == 0 + ); + + if (hasEmptyArray) + { + writer.WritePropertyName(OpenApiConstants.Examples); + writer.WriteStartObject(); + foreach (var kvp in examples.Where(static kvp => kvp.Value.Value is OpenApiArray arr && arr.Count == 0)) + { + writer.WritePropertyName(kvp.Key); + writer.WriteStartObject(); + writer.WriteRequiredObject(OpenApiConstants.Value, kvp.Value.Value, (w, v) => w.WriteAny(v)); + writer.WriteEndObject(); + } + writer.WriteEndObject(); + } + else + { + writer.WriteOptionalMap(OpenApiConstants.Examples, examples, (w, e) => e.SerializeAsV3(w)); + } + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs index 8e3a6c864..266809561 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs @@ -4,9 +4,11 @@ using System.IO; using FluentAssertions; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Readers.ParseNodes; using Microsoft.OpenApi.Readers.V3; +using Microsoft.OpenApi.Tests; using Xunit; namespace Microsoft.OpenApi.Readers.Tests.V3Tests @@ -77,5 +79,43 @@ public void ParseMediaTypeWithExamplesShouldSucceed() } }); } + + [Fact] + public void ParseMediaTypeWithEmptyArrayInExamplesWorks() + { + // Arrange + var expected = @"{ + ""schema"": { + ""type"": ""array"", + ""items"": { + ""type"": ""object"", + ""properties"": { + ""id"": { + ""type"": ""string"" + } + } + } + }, + ""examples"": { + ""Success response - no results"": { + ""value"": [ ] + } + } +} +"; + MapNode node; + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "examplesWithEmptyArray.json"))) + { + node = TestHelper.CreateYamlMapNode(stream); + } + + // Act + var mediaType = OpenApiV3Deserializer.LoadMediaType(node); + var serialized = mediaType.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + + // Assert + serialized.MakeLineBreaksEnvironmentNeutral() + .Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral()); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiMediaType/examplesWithEmptyArray.json b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiMediaType/examplesWithEmptyArray.json new file mode 100644 index 000000000..0d13dcaf2 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiMediaType/examplesWithEmptyArray.json @@ -0,0 +1,18 @@ +{ + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + } + }, + "examples": { + "Success response - no results": { + "value": [] + } + } +} \ No newline at end of file