Skip to content

Commit cb39741

Browse files
Deprecate SerializeAsV2 (#3286)
As a path towards OpenAPI v3.1 support, deprecate the `--serializeasv2`/`SerializeAsV2` options in favour of a new `--openapiversion`/`OpenApiVersion` option that accepts the specification version to use.
1 parent 114c2f0 commit cb39741

File tree

24 files changed

+311
-126
lines changed

24 files changed

+311
-126
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ By default, Swashbuckle will generate and expose Swagger JSON in version 3.0 of
305305
```csharp
306306
app.UseSwagger(c =>
307307
{
308-
c.SerializeAsV2 = true;
308+
c.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0;
309309
});
310310
```
311311

src/Swashbuckle.AspNetCore.Cli/Program.cs

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88
using Microsoft.Extensions.DependencyInjection;
99
using Microsoft.Extensions.Hosting;
1010
using Microsoft.Extensions.Options;
11+
using Microsoft.OpenApi;
1112
using Microsoft.OpenApi.Writers;
1213
using Swashbuckle.AspNetCore.Swagger;
1314

1415
namespace Swashbuckle.AspNetCore.Cli
1516
{
1617
internal class Program
1718
{
19+
private const string OpenApiVersionOption = "--openapiversion";
20+
private const string SerializeAsV2Flag = "--serializeasv2";
21+
1822
public static int Main(string[] args)
1923
{
2024
// Helper to simplify command line parsing etc.
@@ -26,25 +30,28 @@ public static int Main(string[] args)
2630
// startupassembly and it's transitive dependencies. See https://github.com/dotnet/coreclr/issues/13277 for more.
2731

2832
// > dotnet swagger tofile ...
29-
runner.SubCommand("tofile", "retrieves Swagger from a startup assembly, and writes to file ", c =>
33+
runner.SubCommand("tofile", "retrieves Swagger from a startup assembly, and writes to file", c =>
3034
{
3135
c.Argument("startupassembly", "relative path to the application's startup assembly");
3236
c.Argument("swaggerdoc", "name of the swagger doc you want to retrieve, as configured in your startup class");
3337

3438
c.Option("--output", "relative path where the Swagger will be output, defaults to stdout");
3539
c.Option("--host", "a specific host to include in the Swagger output");
3640
c.Option("--basepath", "a specific basePath to include in the Swagger output");
37-
c.Option("--serializeasv2", "output Swagger in the V2 format rather than V3", true);
41+
c.Option(OpenApiVersionOption, "output Swagger in the specified version, defaults to 3.0");
3842
c.Option("--yaml", "exports swagger in a yaml format", true);
3943

44+
// TODO Remove this option in the major version that adds support for OpenAPI 3.1
45+
c.Option(SerializeAsV2Flag, "output Swagger in the V2 format rather than V3 [deprecated]", true);
46+
4047
c.OnRun((namedArgs) =>
4148
{
4249
string subProcessCommandLine = PrepareCommandLine(args, namedArgs);
4350

44-
var subProcess = Process.Start("dotnet", subProcessCommandLine);
51+
using var child = Process.Start("dotnet", subProcessCommandLine);
4552

46-
subProcess.WaitForExit();
47-
return subProcess.ExitCode;
53+
child.WaitForExit();
54+
return child.ExitCode;
4855
});
4956
});
5057

@@ -56,8 +63,12 @@ public static int Main(string[] args)
5663
c.Option("--output", "");
5764
c.Option("--host", "");
5865
c.Option("--basepath", "");
59-
c.Option("--serializeasv2", "", true);
66+
c.Option(OpenApiVersionOption, "");
6067
c.Option("--yaml", "", true);
68+
69+
// TODO Remove this option in the major version that adds support for OpenAPI 3.1
70+
c.Option(SerializeAsV2Flag, "", true);
71+
6172
c.OnRun((namedArgs) =>
6273
{
6374
SetupAndRetrieveSwaggerProviderAndOptions(namedArgs, out var swaggerProvider, out var swaggerOptions);
@@ -94,24 +105,40 @@ public static int Main(string[] args)
94105
writer = new OpenApiJsonWriter(streamWriter);
95106
}
96107

97-
if (namedArgs.ContainsKey("--serializeasv2"))
108+
OpenApiSpecVersion specVersion = OpenApiSpecVersion.OpenApi3_0;
109+
110+
if (namedArgs.TryGetValue(OpenApiVersionOption, out var versionArg))
98111
{
99-
if (swaggerDocumentSerializer != null)
112+
specVersion = versionArg switch
100113
{
101-
swaggerDocumentSerializer.SerializeDocument(swagger, writer, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0);
102-
}
103-
else
104-
{
105-
swagger.SerializeAsV2(writer);
106-
}
114+
"2.0" => OpenApiSpecVersion.OpenApi2_0,
115+
"3.0" => OpenApiSpecVersion.OpenApi3_0,
116+
_ => throw new NotSupportedException($"The specified OpenAPI version \"{versionArg}\" is not supported."),
117+
};
107118
}
108-
else if (swaggerDocumentSerializer != null)
119+
else if (namedArgs.ContainsKey(SerializeAsV2Flag))
120+
{
121+
specVersion = OpenApiSpecVersion.OpenApi2_0;
122+
WriteSerializeAsV2DeprecationWarning();
123+
}
124+
125+
if (swaggerDocumentSerializer != null)
109126
{
110-
swaggerDocumentSerializer.SerializeDocument(swagger, writer, Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0);
127+
swaggerDocumentSerializer.SerializeDocument(swagger, writer, specVersion);
111128
}
112129
else
113130
{
114-
swagger.SerializeAsV3(writer);
131+
switch (specVersion)
132+
{
133+
case OpenApiSpecVersion.OpenApi2_0:
134+
swagger.SerializeAsV2(writer);
135+
break;
136+
137+
case OpenApiSpecVersion.OpenApi3_0:
138+
default:
139+
swagger.SerializeAsV3(writer);
140+
break;
141+
}
115142
}
116143

117144
if (outputPath != null)
@@ -132,10 +159,10 @@ public static int Main(string[] args)
132159
{
133160
string subProcessCommandLine = PrepareCommandLine(args, namedArgs);
134161

135-
var subProcess = Process.Start("dotnet", subProcessCommandLine);
162+
using var child = Process.Start("dotnet", subProcessCommandLine);
136163

137-
subProcess.WaitForExit();
138-
return subProcess.ExitCode;
164+
child.WaitForExit();
165+
return child.ExitCode;
139166
});
140167
});
141168

@@ -147,7 +174,7 @@ public static int Main(string[] args)
147174
c.OnRun((namedArgs) =>
148175
{
149176
SetupAndRetrieveSwaggerProviderAndOptions(namedArgs, out var swaggerProvider, out var swaggerOptions);
150-
IList<string> docNames = new List<string>();
177+
IList<string> docNames = [];
151178

152179
string outputPath = namedArgs.TryGetValue("--output", out var arg1)
153180
? Path.Combine(Directory.GetCurrentDirectory(), arg1)
@@ -185,7 +212,7 @@ public static int Main(string[] args)
185212
return runner.Run(args);
186213
}
187214

188-
private static void SetupAndRetrieveSwaggerProviderAndOptions(System.Collections.Generic.IDictionary<string, string> namedArgs, out ISwaggerProvider swaggerProvider, out IOptions<SwaggerOptions> swaggerOptions)
215+
private static void SetupAndRetrieveSwaggerProviderAndOptions(IDictionary<string, string> namedArgs, out ISwaggerProvider swaggerProvider, out IOptions<SwaggerOptions> swaggerOptions)
189216
{
190217
// 1) Configure host with provided startupassembly
191218
var startupAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(
@@ -199,7 +226,7 @@ private static void SetupAndRetrieveSwaggerProviderAndOptions(System.Collections
199226
swaggerOptions = serviceProvider.GetService<IOptions<SwaggerOptions>>();
200227
}
201228

202-
private static string PrepareCommandLine(string[] args, System.Collections.Generic.IDictionary<string, string> namedArgs)
229+
private static string PrepareCommandLine(string[] args, IDictionary<string, string> namedArgs)
203230
{
204231
if (!File.Exists(namedArgs["startupassembly"]))
205232
{
@@ -222,7 +249,7 @@ private static string PrepareCommandLine(string[] args, System.Collections.Gener
222249
EscapePath(runtimeConfig),
223250
EscapePath(typeof(Program).GetTypeInfo().Assembly.Location),
224251
commandName,
225-
string.Join(" ", subProcessArguments.Select(x => EscapePath(x)))
252+
string.Join(" ", subProcessArguments.Select(EscapePath))
226253
);
227254
return subProcessCommandLine;
228255
}
@@ -301,5 +328,21 @@ private static bool TryGetCustomHost<THost>(
301328
host = (THost)factoryMethod.Invoke(null, null);
302329
return true;
303330
}
331+
332+
private static void WriteSerializeAsV2DeprecationWarning()
333+
{
334+
const string AppName = "Swashbuckle.AspNetCore.Cli";
335+
336+
string message = $"The {SerializeAsV2Flag} flag will be removed in a future version of {AppName}. Use the {OpenApiVersionOption} option instead.";
337+
338+
Console.WriteLine(message);
339+
340+
// See https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-a-warning-message
341+
// and https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables
342+
if (Environment.GetEnvironmentVariable("GITHUB_ACTIONS") is "true")
343+
{
344+
Console.WriteLine($"::warning title={AppName}::{message}");
345+
}
346+
}
304347
}
305348
}

src/Swashbuckle.AspNetCore.Swagger/DependencyInjection/SwaggerBuilderExtensions.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,22 @@ public static IEndpointConventionBuilder MapSwagger(
5353
throw new ArgumentException("Pattern must contain '{documentName}' parameter", nameof(pattern));
5454
}
5555

56-
Action<SwaggerOptions> endpointSetupAction = options =>
56+
var pipeline = endpoints.CreateApplicationBuilder()
57+
.UseSwagger(Configure)
58+
.Build();
59+
60+
return endpoints.MapGet(pattern, pipeline);
61+
62+
void Configure(SwaggerOptions options)
5763
{
5864
var endpointOptions = new SwaggerEndpointOptions();
5965

6066
setupAction?.Invoke(endpointOptions);
6167

6268
options.RouteTemplate = pattern;
63-
options.SerializeAsV2 = endpointOptions.SerializeAsV2;
69+
options.OpenApiVersion = endpointOptions.OpenApiVersion;
6470
options.PreSerializeFilters.AddRange(endpointOptions.PreSerializeFilters);
65-
};
66-
67-
var pipeline = endpoints.CreateApplicationBuilder()
68-
.UseSwagger(endpointSetupAction)
69-
.Build();
70-
71-
return endpoints.MapGet(pattern, pipeline);
71+
}
7272
}
7373
#endif
7474
}

src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Shipped.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,13 @@ Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentMetadataProvider
1515
Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentMetadataProvider.GetDocumentNames() -> System.Collections.Generic.IList<string>
1616
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions
1717
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.PreSerializeFilters.get -> System.Collections.Generic.List<System.Action<Microsoft.OpenApi.Models.OpenApiDocument, Microsoft.AspNetCore.Http.HttpRequest>>
18-
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.get -> bool
19-
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.set -> void
2018
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SwaggerEndpointOptions() -> void
2119
Swashbuckle.AspNetCore.Swagger.SwaggerOptions
2220
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.CustomDocumentSerializer.get -> Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentSerializer
2321
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.CustomDocumentSerializer.set -> void
2422
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.PreSerializeFilters.get -> System.Collections.Generic.List<System.Action<Microsoft.OpenApi.Models.OpenApiDocument, Microsoft.AspNetCore.Http.HttpRequest>>
2523
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.RouteTemplate.get -> string
2624
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.RouteTemplate.set -> void
27-
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.get -> bool
28-
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.set -> void
2925
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SwaggerOptions() -> void
3026
Swashbuckle.AspNetCore.Swagger.UnknownSwaggerDocument
3127
Swashbuckle.AspNetCore.Swagger.UnknownSwaggerDocument.UnknownSwaggerDocument(string documentName, System.Collections.Generic.IEnumerable<string> knownDocuments) -> void
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.OpenApiVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion
2+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.OpenApiVersion.set -> void
3+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.OpenApiVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion
4+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.OpenApiVersion.set -> void
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.get -> bool
2+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.set -> void
3+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.get -> bool
4+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.set -> void

src/Swashbuckle.AspNetCore.Swagger/PublicAPI/net6.0/PublicAPI.Unshipped.txt

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.get -> bool
2+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.set -> void
3+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.get -> bool
4+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.set -> void

src/Swashbuckle.AspNetCore.Swagger/PublicAPI/net8.0/PublicAPI.Unshipped.txt

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.get -> bool
2+
Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SerializeAsV2.set -> void
3+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.get -> bool
4+
Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SerializeAsV2.set -> void

0 commit comments

Comments
 (0)