From 00ec76d49749b8ee55482f37e458c3e2005462da Mon Sep 17 00:00:00 2001 From: Mahdi Golestan Date: Wed, 22 Jul 2026 15:53:50 +0330 Subject: [PATCH] feat: add SerializeAsJsonAsync overloads accepting OpenApiJsonWriterSettings --- .../OpenApiSerializableExtensions.cs | 65 ++++++++++++++++++- src/Microsoft.OpenApi/PublicAPI.Unshipped.txt | 3 + .../OpenApiSerializableExtensionsTests.cs | 56 ++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs index a1f2aca4d..d67493f8b 100755 --- a/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs +++ b/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Globalization; @@ -21,12 +21,28 @@ public static class OpenApiSerializableExtensions /// The output stream. /// The Open API specification version. /// The cancellation token. +#pragma warning disable RS0027 // The settings overload below has the same parameter count but different types; no ambiguity exists. public static Task SerializeAsJsonAsync(this T element, Stream stream, OpenApiSpecVersion specVersion, CancellationToken cancellationToken = default) +#pragma warning restore RS0027 where T : IOpenApiSerializable { return element.SerializeAsync(stream, specVersion, OpenApiConstants.Json, cancellationToken); } + /// + /// Serialize the to the Open API document (JSON) using the given stream, specification version and settings. + /// + /// the + /// The Open API element. + /// The output stream. + /// The Open API specification version. + /// Settings controlling JSON output, including for compact formatting. + public static Task SerializeAsJsonAsync(this T element, Stream stream, OpenApiSpecVersion specVersion, OpenApiJsonWriterSettings settings) + where T : IOpenApiSerializable + { + return element.SerializeAsync(stream, specVersion, OpenApiConstants.Json, settings, CancellationToken.None); + } + /// /// Serializes the to the Open API document (YAML) using the given stream and specification version. /// @@ -104,7 +120,9 @@ public static Task SerializeAsync( /// The output writer. /// Version of the specification the output should conform to /// The cancellation token. +#pragma warning disable RS0027 // The settings-bearing SerializeAsync overloads below have the same parameter count but different types; no ambiguity exists. public static Task SerializeAsync(this T element, IOpenApiWriter writer, OpenApiSpecVersion specVersion, CancellationToken cancellationToken = default) +#pragma warning restore RS0027 where T : IOpenApiSerializable { Utils.CheckArgumentNull(element); @@ -142,15 +160,33 @@ public static Task SerializeAsync(this T element, IOpenApiWriter writer, Open /// The Open API element. /// The Open API specification version. /// The cancellation token. +#pragma warning disable RS0027 // The settings overload below has the same parameter count but different types; no ambiguity exists. public static Task SerializeAsJsonAsync( this T element, OpenApiSpecVersion specVersion, CancellationToken cancellationToken = default) +#pragma warning restore RS0027 where T : IOpenApiSerializable { return element.SerializeAsync(specVersion, OpenApiConstants.Json, cancellationToken); } + /// + /// Serializes the to the Open API document as a string in JSON format using the given settings. + /// + /// the + /// The Open API element. + /// The Open API specification version. + /// Settings controlling JSON output, including for compact formatting. + public static Task SerializeAsJsonAsync( + this T element, + OpenApiSpecVersion specVersion, + OpenApiJsonWriterSettings settings) + where T : IOpenApiSerializable + { + return element.SerializeAsync(specVersion, OpenApiConstants.Json, settings); + } + /// /// Serializes the to the Open API document as a string in YAML format. /// @@ -175,11 +211,13 @@ public static Task SerializeAsYamlAsync( /// The Open API specification version. /// Open API document format. /// The cancellation token. +#pragma warning disable RS0027 // The settings overload below has the same parameter count but different types; no ambiguity exists. public static async Task SerializeAsync( this T element, OpenApiSpecVersion specVersion, string format, CancellationToken cancellationToken = default) +#pragma warning restore RS0027 where T : IOpenApiSerializable { Utils.CheckArgumentNull(element); @@ -195,5 +233,30 @@ public static async Task SerializeAsync( return await streamReader.ReadToEndAsync().ConfigureAwait(false); #endif } + + /// + /// Serializes the to the Open API document as a string in the given format using the given settings. + /// + /// the + /// The Open API element. + /// The Open API specification version. + /// Open API document format. + /// Provide configuration settings for controlling writing output. + public static async Task SerializeAsync( + this T element, + OpenApiSpecVersion specVersion, + string format, + OpenApiWriterSettings? settings) + where T : IOpenApiSerializable + { + Utils.CheckArgumentNull(element); + + using var stream = new MemoryStream(); + await element.SerializeAsync(stream, specVersion, format, settings, CancellationToken.None).ConfigureAwait(false); + stream.Position = 0; + + using var streamReader = new StreamReader(stream); + return await streamReader.ReadToEndAsync().ConfigureAwait(false); + } } } diff --git a/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt index 4699f67cc..99b9f0247 100644 --- a/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi/PublicAPI.Unshipped.txt @@ -1,3 +1,6 @@ #nullable enable const Microsoft.OpenApi.OpenApiConstants.JsonSchemaExamplesExtension = "x-jsonschema-examples" -> string! const Microsoft.OpenApi.OpenApiConstants.OaiLicenseIdentifier = "x-oai-license-identifier" -> string! +static Microsoft.OpenApi.OpenApiSerializableExtensions.SerializeAsJsonAsync(this T element, Microsoft.OpenApi.OpenApiSpecVersion specVersion, Microsoft.OpenApi.OpenApiJsonWriterSettings! settings) -> System.Threading.Tasks.Task! +static Microsoft.OpenApi.OpenApiSerializableExtensions.SerializeAsJsonAsync(this T element, System.IO.Stream! stream, Microsoft.OpenApi.OpenApiSpecVersion specVersion, Microsoft.OpenApi.OpenApiJsonWriterSettings! settings) -> System.Threading.Tasks.Task! +static Microsoft.OpenApi.OpenApiSerializableExtensions.SerializeAsync(this T element, Microsoft.OpenApi.OpenApiSpecVersion specVersion, string! format, Microsoft.OpenApi.OpenApiWriterSettings? settings) -> System.Threading.Tasks.Task! diff --git a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiSerializableExtensionsTests.cs b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiSerializableExtensionsTests.cs index a1e323ebf..f55fb7061 100644 --- a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiSerializableExtensionsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiSerializableExtensionsTests.cs @@ -90,4 +90,60 @@ public async Task UsesTheTerseOutputInformationFromSettingsNoSettings() Assert.Equal("{\n \"name\": \"param1\",\n \"in\": \"query\",\n \"description\": \"A sample parameter\",\n \"schema\": {\n \"type\": \"string\"\n }\n}", output); } + + [Fact] + public async Task SerializeAsJsonAsync_WithTerseSettings_WritesToStream() + { + var parameter = new OpenApiParameter + { + Name = "param1", + In = ParameterLocation.Query, + Schema = new OpenApiSchema { Type = JsonSchemaType.String } + }; + + var settings = new OpenApiJsonWriterSettings { Terse = true }; + + using var stream = new MemoryStream(); + await parameter.SerializeAsJsonAsync(stream, OpenApiSpecVersion.OpenApi3_1, settings); + + stream.Position = 0; + using var reader = new StreamReader(stream); + var output = await reader.ReadToEndAsync(); + + Assert.Equal("{\"name\":\"param1\",\"in\":\"query\",\"schema\":{\"type\":\"string\"}}", output); + } + + [Fact] + public async Task SerializeAsJsonAsync_WithTerseSettings_ReturnsCompactString() + { + var parameter = new OpenApiParameter + { + Name = "param1", + In = ParameterLocation.Query, + Schema = new OpenApiSchema { Type = JsonSchemaType.String } + }; + + var settings = new OpenApiJsonWriterSettings { Terse = true }; + + var output = await parameter.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_1, settings); + + Assert.Equal("{\"name\":\"param1\",\"in\":\"query\",\"schema\":{\"type\":\"string\"}}", output); + } + + [Fact] + public async Task SerializeAsync_WithSettings_ReturnsFormattedString() + { + var parameter = new OpenApiParameter + { + Name = "param1", + In = ParameterLocation.Query, + Schema = new OpenApiSchema { Type = JsonSchemaType.String } + }; + + var settings = new OpenApiJsonWriterSettings { Terse = false }; + + var output = await parameter.SerializeAsync(OpenApiSpecVersion.OpenApi3_1, OpenApiConstants.Json, settings); + + Assert.Equal("{\n \"name\": \"param1\",\n \"in\": \"query\",\n \"schema\": {\n \"type\": \"string\"\n }\n}", output); + } }