diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cce780733f..18b5a96719 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -43,5 +43,5 @@ updates: - dependency-name: "Microsoft.AspNetCore.Mvc.NewtonsoftJson" - dependency-name: "Microsoft.AspNetCore.Mvc.Testing" - dependency-name: "Microsoft.OpenApi" - - dependency-name: "Microsoft.OpenApi.Readers" + - dependency-name: "Microsoft.OpenApi.YamlReader" - dependency-name: "xunit" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 0a51eb63f5..b5847a4f55 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -1,28 +1,28 @@ -name: dependency-review - -on: - pull_request: - branches: [ master, dotnet-vnext ] - -permissions: {} - -jobs: - dependency-review: - runs-on: ubuntu-latest - - permissions: - contents: read - - steps: - - - name: Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - filter: 'tree:0' - persist-credentials: false - show-progress: false - - - name: Review dependencies +name: dependency-review + +on: + pull_request: + branches: [ master, dotnet-vnext ] + +permissions: {} + +jobs: + dependency-review: + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + + - name: Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + filter: 'tree:0' + persist-credentials: false + show-progress: false + + - name: Review dependencies uses: actions/dependency-review-action@40c09b7dc99638e5ddb0bfd91c1673effc064d8a # v4.8.1 - with: - allow-licenses: '(MPL-2.0 OR Apache-2.0),0BSD,Apache-2.0,BSD-2-Clause,BSD-3-Clause,ISC,MIT,Python-2.0,LicenseRef-scancode-generic-cla AND MIT' + with: + allow-licenses: '(MPL-2.0 OR Apache-2.0),0BSD,Apache-2.0,BSD-2-Clause,BSD-3-Clause,ISC,MIT,Python-2.0,LicenseRef-scancode-generic-cla AND MIT' diff --git a/Directory.Build.props b/Directory.Build.props index 9bd7c66fa0..dd68ffe293 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,7 +8,7 @@ https://github.com/domaindrivendev/Swashbuckle.AspNetCore true Copyright (c) 2016-$([System.DateTime]::Now.ToString(yyyy)) Richard Morris - net9.0;net8.0 + net10.0;net9.0;net8.0 true true $(IsPackable) @@ -18,6 +18,8 @@ latest true en-US + + $(NoWarn);NU5104 direct ```cs -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; var builder = WebApplication.CreateBuilder(args); @@ -106,7 +111,7 @@ Then, expose the OpenAPI JSON document endpoint(s) using one of following method // Your own endpoints go here, and then... app.MapSwagger(); ``` -snippet source | anchor +snippet source | anchor @@ -118,7 +123,7 @@ app.MapSwagger(); ```cs app.UseSwagger(); ``` -snippet source | anchor +snippet source | anchor @@ -135,7 +140,7 @@ app.UseSwaggerUI(options => options.SwaggerEndpoint("v1/swagger.json", "My API V1"); }); ``` -snippet source | anchor +snippet source | anchor @@ -208,7 +213,7 @@ app.UseMvc(routes => routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); }); ``` -snippet source | anchor +snippet source | anchor @@ -282,6 +287,7 @@ Check out the table below for the full list of possible configuration options. | ------------- | ----------------------------------- | | **Swashbuckle.AspNetCore.Swagger** | [Change the Path for OpenAPI JSON Endpoints](docs/configure-and-customize-swagger.md#change-the-path-for-openapi-json-endpoints) | | | [Modify OpenAPI with Request Context](docs/configure-and-customize-swagger.md#modify-openapi-with-request-context) | +| | [Serialize OpenAPI JSON in the 3.1 format](docs/configure-and-customize-swagger.md#serialize-openapi-in-the-31-format) | | | [Serialize Swagger JSON in the 2.0 format](docs/configure-and-customize-swagger.md#serialize-swagger-in-the-20-format) | | | [Working with Virtual Directories and Reverse Proxies](docs/configure-and-customize-swagger.md#working-with-virtual-directories-and-reverse-proxies) | | | [Customizing how the OpenAPI document is serialized](docs/configure-and-customize-swagger.md#customizing-how-the-openapi-document-is-serialized) | @@ -341,6 +347,7 @@ Check out the table below for the full list of possible configuration options. [help-wanted-badge]: https://img.shields.io/github/issues/domaindrivendev/Swashbuckle.AspNetCore/help-wanted?style=flat&color=%24EC820&label=Help%20wanted [help-wanted-issues]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/labels/help-wanted "Issues with help wanted for this project" [microelements-swashbuckle-fluentvalidation]: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation "MicroElements.Swashbuckle.FluentValidation on GitHub" +[microsoft-openapi]: https://www.nuget.org/packages/Microsoft.OpenApi "The Microsoft.OpenApi NuGet package" [mmlib-swaggerforocelot]: MMLib.SwaggerForOcelot "MMLib.SwaggerForOcelot on GitHub" [mvc-routing]: https://learn.microsoft.com/aspnet/core/mvc/controllers/routing "Routing to controller actions in ASP.NET Core" [newtonsoft-json]: https://www.nuget.org/packages/Newtonsoft.Json/ "Newtonsoft.Json NuGet package" @@ -365,3 +372,4 @@ Check out the table below for the full list of possible configuration options. [swagger-ui]: https://github.com/swagger-api/swagger-ui "The swagger-ui project in GitHub" [system-text-json]: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/overview "JSON serialization and deserialization in .NET - overview" [unchase-swashbuckle-aspnetcore-extensions]: https://github.com/unchase/Unchase.Swashbuckle.AspNetCore.Extensions "Unchase.Swashbuckle.AspNetCore.Extensions on GitHub" +[v10-migration]: docs/migrating-to-v10.md "Migrating to Swashbuckle.AspNetCore v10" diff --git a/docs/configure-and-customize-annotations.md b/docs/configure-and-customize-annotations.md index 1ec8f84c95..86c041deea 100644 --- a/docs/configure-and-customize-annotations.md +++ b/docs/configure-and-customize-annotations.md @@ -178,17 +178,20 @@ public class Item ```cs public class ItemSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { - schema.Example = new OpenApiObject + if (schema is OpenApiSchema concrete) { - ["Id"] = new OpenApiInteger(1), - ["Description"] = new OpenApiString("An awesome item") - }; + concrete.Example = new JsonObject + { + ["Id"] = 1, + ["Description"] = "An awesome item" + }; + } } } ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/configure-and-customize-redoc.md b/docs/configure-and-customize-redoc.md index df34563adb..82f24a8166 100644 --- a/docs/configure-and-customize-redoc.md +++ b/docs/configure-and-customize-redoc.md @@ -13,7 +13,7 @@ app.UseReDoc(options => options.RoutePrefix = "docs"; }); ``` -snippet source | anchor +snippet source | anchor @@ -30,7 +30,7 @@ app.UseReDoc(options => options.DocumentTitle = "My API Docs"; }); ``` -snippet source | anchor +snippet source | anchor @@ -61,7 +61,7 @@ app.UseReDoc(options => options.SortPropsAlphabetically(); }); ``` -snippet source | anchor +snippet source | anchor @@ -82,7 +82,7 @@ app.UseReDoc(options => options.InjectStylesheet("/redoc/custom.css"); }); ``` -snippet source | anchor +snippet source | anchor @@ -101,7 +101,7 @@ app.UseReDoc(options => }; }); ``` -snippet source | anchor +snippet source | anchor @@ -119,7 +119,7 @@ app.UseReDoc(options => .GetManifestResourceStream("CustomIndex.ReDoc.index.html"); // Requires file to be added as an embedded resource }); ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/configure-and-customize-swagger.md b/docs/configure-and-customize-swagger.md index ef390e0bdd..3e80e350c9 100644 --- a/docs/configure-and-customize-swagger.md +++ b/docs/configure-and-customize-swagger.md @@ -17,7 +17,7 @@ app.UseSwagger(options => options.RouteTemplate = "api-docs/{documentName}/swagger.json"; }); ``` -snippet source | anchor +snippet source | anchor @@ -50,7 +50,7 @@ app.UseSwagger(options => }); }); ``` -snippet source | anchor +snippet source | anchor @@ -58,6 +58,25 @@ The `OpenApiDocument` and the current `HttpRequest` are both passed to the filte For example, you can add an explicit API server based on the `Host` header (as shown), or you could inspect session information or an `Authorization` header and remove operations from the document based on user permissions. +## Serialize OpenAPI in the 3.1 format + +By default, Swashbuckle.AspNetCore will generate and expose OpenAPI JSON in version 3.0 of the specification. +However, if you wish to use the latest version of the OpenAPI specification, you can opt into version 3.1 +format with the following option: + + + + +```cs +app.UseSwagger(options => +{ + options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1; +}); +``` +snippet source | anchor + + + ## Serialize Swagger in the 2.0 format By default, Swashbuckle will generate and expose OpenAPI JSON in version 3.0 of the specification, officially called the @@ -73,7 +92,7 @@ app.UseSwagger(options => options.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0; }); ``` -snippet source | anchor +snippet source | anchor @@ -98,7 +117,7 @@ app.UseSwaggerUI(options => options.SwaggerEndpoint("v1/swagger.json", "My API V1"); }); ``` -snippet source | anchor +snippet source | anchor @@ -136,6 +155,6 @@ app.UseSwagger(options => options.SetCustomDocumentSerializer(); }); ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/configure-and-customize-swaggergen.md b/docs/configure-and-customize-swaggergen.md index 6310c3ec27..53e187efd2 100644 --- a/docs/configure-and-customize-swaggergen.md +++ b/docs/configure-and-customize-swaggergen.md @@ -786,7 +786,7 @@ public class PhoneNumber ```cs services.AddSwaggerGen(options => { - options.MapType(() => new OpenApiSchema { Type = "string" }); + options.MapType(() => new OpenApiSchema { Type = JsonSchemaType.String }); }); ``` snippet source | anchor @@ -871,24 +871,27 @@ to inform the AutoRest tool how enums should be modelled when it generates the A ```cs public class AutoRestSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { var type = context.Type; - if (type.IsEnum) + if (type.IsEnum && schema is OpenApiSchema concrete) { - schema.Extensions.Add( + concrete.Extensions ??= new Dictionary(); + concrete.Extensions.Add( "x-ms-enum", - new OpenApiObject - { - ["name"] = new OpenApiString(type.Name), - ["modelAsString"] = new OpenApiBoolean(true) - } + new JsonNodeExtension( + new JsonObject + { + ["name"] = type.Name, + ["modelAsString"] = true + } + ) ); } } } ``` -snippet source | anchor +snippet source | anchor @@ -919,8 +922,13 @@ so you will need [a special JsonConverter, as shown in the .NET documentation](h ```cs public class DictionaryTKeyEnumTValueSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { + if (schema is not OpenApiSchema concrete) + { + return; + } + // Only run for fields that are a Dictionary if (!context.Type.IsGenericType || !context.Type.GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>))) { @@ -936,14 +944,14 @@ public class DictionaryTKeyEnumTValueSchemaFilter : ISchemaFilter return; } - schema.Type = "object"; - schema.Properties = keyType.GetEnumNames().ToDictionary( + concrete.Type = JsonSchemaType.Object; + concrete.Properties = keyType.GetEnumNames().ToDictionary( name => name, name => context.SchemaGenerator.GenerateSchema(valueType, context.SchemaRepository)); } } ``` -snippet source | anchor +snippet source | anchor @@ -981,11 +989,11 @@ public class TagDescriptionsDocumentFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { - swaggerDoc.Tags = - [ - new OpenApiTag { Name = "Products", Description = "Browse/manage the product catalog" }, - new OpenApiTag { Name = "Orders", Description = "Submit orders" } - ]; + swaggerDoc.Tags = new HashSet() + { + new() { Name = "Products", Description = "Browse/manage the product catalog" }, + new() { Name = "Orders", Description = "Submit orders" } + }; } } ``` @@ -1051,19 +1059,13 @@ services.AddSwaggerGen(options => ```cs services.AddSwaggerGen(options => { - options.AddSecurityRequirement(new OpenApiSecurityRequirement + options.AddSecurityRequirement((document) => new OpenApiSecurityRequirement() { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } - }, - ["readAccess", "writeAccess"] - } + [new OpenApiSecuritySchemeReference("oauth2", document)] = ["readAccess", "writeAccess"] }); }); ``` -snippet source | anchor +snippet source | anchor @@ -1094,10 +1096,7 @@ public class SecurityRequirementsOperationFilter : IOperationFilter operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" }); - var scheme = new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } - }; + var scheme = new OpenApiSecuritySchemeReference("oauth2", context.Document); operation.Security = [ @@ -1110,7 +1109,7 @@ public class SecurityRequirementsOperationFilter : IOperationFilter } } ``` -snippet source | anchor +snippet source | anchor @@ -1133,19 +1132,13 @@ services.AddSwaggerGen(options => BearerFormat = "JWT", Description = "JWT Authorization header using the Bearer scheme." }); - options.AddSecurityRequirement(new OpenApiSecurityRequirement + options.AddSecurityRequirement(document => new OpenApiSecurityRequirement { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" } - }, - [] - } + [new OpenApiSecuritySchemeReference("bearer", document)] = [] }); }); ``` -snippet source | anchor +snippet source | anchor @@ -1237,7 +1230,7 @@ services.AddSwaggerGen(options => }); }); ``` -snippet source | anchor +snippet source | anchor @@ -1319,7 +1312,7 @@ services.AddSwaggerGen(options => options.SelectDiscriminatorValueUsing((subType) => subType.Name); }); ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/configure-and-customize-swaggerui.md b/docs/configure-and-customize-swaggerui.md index 27af2bcac2..8dfcf90efa 100644 --- a/docs/configure-and-customize-swaggerui.md +++ b/docs/configure-and-customize-swaggerui.md @@ -13,7 +13,7 @@ app.UseSwaggerUI(options => options.RoutePrefix = "api-docs"; }); ``` -snippet source | anchor +snippet source | anchor @@ -31,7 +31,7 @@ app.UseSwaggerUI(options => options.DocumentTitle = "My Swagger UI"; }); ``` -snippet source | anchor +snippet source | anchor @@ -51,7 +51,7 @@ app.UseSwaggerUI(options => options.ScriptPresetsPath = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.29.1/swagger-ui-standalone-preset.min.js"; }); ``` -snippet source | anchor +snippet source | anchor @@ -71,7 +71,7 @@ app.UseSwaggerUI(options => options.SwaggerEndpoint("/swagger/v2/swagger.json", "V2 Docs"); }); ``` -snippet source | anchor +snippet source | anchor @@ -106,7 +106,7 @@ app.UseSwaggerUI(options => options.UseResponseInterceptor("(response) => { return response; }"); }); ``` -snippet source | anchor +snippet source | anchor @@ -124,7 +124,7 @@ app.UseSwaggerUI(options => options.InjectJavascript("/swagger-ui/custom.js"); }); ``` -snippet source | anchor +snippet source | anchor @@ -142,7 +142,7 @@ app.UseSwaggerUI(options => options.InjectStylesheet("/swagger-ui/custom.css"); }); ``` -snippet source | anchor +snippet source | anchor @@ -160,7 +160,7 @@ app.UseSwaggerUI(options => .GetManifestResourceStream("CustomUIIndex.Swagger.index.html"); // Requires file to be added as an embedded resource }); ``` -snippet source | anchor +snippet source | anchor @@ -205,7 +205,7 @@ app.UseSwaggerUI(options => options.OAuthUsePkce(); }); ``` -snippet source | anchor +snippet source | anchor @@ -224,7 +224,7 @@ app.UseSwaggerUI(options => options.UseResponseInterceptor("(res) => { console.log('Custom interceptor intercepted response from:', res.url); return res; }"); }); ``` -snippet source | anchor +snippet source | anchor @@ -239,7 +239,7 @@ app.UseSwaggerUI(options => options.UseRequestInterceptor("(req) => { req.headers['X-XSRF-Token'] = localStorage.getItem('xsrf-token'); return req; }"); }); ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/migrating-to-v10.md b/docs/migrating-to-v10.md new file mode 100644 index 0000000000..472adc7b27 --- /dev/null +++ b/docs/migrating-to-v10.md @@ -0,0 +1,85 @@ +# Migrating to Swashbuckle.AspNetCore v10 + +> [!IMPORTANT] +> This document describes the breaking changes introduced in Swashbuckle.AspNetCore v10, and how to migrate from v9.x to v10+. + +## Why breaking changes? + +While the [OpenAPI 3.1 specification][openapi-specification] is a minor release compared to OpenAPI 3.0, the OpenAPI specification does +not use Semantic Versioning (SemVer). The changes introduced between the two versions are quite breaking in a practical sense, so major +changes were required to be made to [Microsoft.OpenApi][microsoft-openapi-package], the package which Swashbuckle.AspNetCore builds upon, +in order to allow applications to produce OpenAPI 3.1 documents. + +These changes were introduced in [Microsoft.OpenApi v2.0.0][microsoft-openapi-v2-migration-guide], which _does_ follow SemVer. As a result, +Swashbuckle.AspNetCore v10+ now depends on Microsoft.OpenApi v2+ to allow users to produce OpenAPI 3.1 documents, fulfilling a +long-standing feature request: [Plans on official support for OpenApi 3.1.0 #2349][feature-request]. + +These changes are unfortunately required, even if you still wish to target Swagger 2.0 or OpenAPI 3.0 documents, as the same library is used +to produce all three document format versions. + +For the same breaking changes, ASP.NET Core v10+ also depends on Microsoft.OpenApi v2+, so these changes were also required to allow applications +using ASP.NET Core 10 to use Swashbuckle.AspNetCore effectively with minimal friction. This also helps support users who may wish to migrate an +application from Swashbuckle.AspNetCore to Microsoft.AspNetCore.OpenApi (for example if they need native AoT support). More information about the +breaking changes in ASP.NET Core 10 can be found in this document: _[What's new in ASP.NET Core in .NET 10][breaking-changes-aspnetcore]_. + +The refactoring required to support OpenAPI 3.1 in Swashbuckle.AspNetCore was significant. If you're interested in what exactly what was changed, +you can check out the PR to implement it that was worked on over the course of .NET 10's development (it's quite large): _[Support .NET 10 #3283][swashbuckle-aspnetcore-10]_. + +## How do I enable OpenAPI 3.1 support? + +By default, to minimise breaking _behavioural_ changes, Swashbuckle.AspNetCore v10+ will continue to produce OpenAPI 3.0 documents by default. + +To upgrade your OpenAPI documents to output using version 3.1 of the OpenAPI specification, you can override the version as shown in the code snippet below. + + + + +```cs +app.UseSwagger(options => +{ + options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1; +}); +``` +snippet source | anchor + + + +## How do I migrate to Swashbuckle.AspNetCore v10+? + +The majority of the breaking changes you may encounter when migrating to Swashbuckle.AspNetCore v10+ are due to the underlying +changes in Microsoft.OpenApi v2.0.0+. The [v2 migration guide for Microsoft.OpenApi][microsoft-openapi-v2-migration-guide] provides a +detailed overview of the breaking changes and how to migrate your code from Microsoft.OpenApi v1.x to v2.x. The Microsoft.OpenApi +breaking changes document should be your primary reference when migrating to Swashbuckle.AspNetCore v10+. + +The chances of encountering breaking changes when migrating to Swashbuckle.AspNetCore v10+ depend on how extensively you use the +Swashbuckle.AspNetCore extensibility points, such as custom filters, to generate the OpenAPI document. If you do not use any custom logic +and do not depend on any other third-party libraries that depend on Microsoft.OpenApi v1.x, you may not encounter any breaking changes at all. + +In cases where Swashbuckle.AspNetCore has a breaking change, this is because the types from the underlying Microsoft.OpenApi library +are exposed in the public API of Swashbuckle.AspNetCore, so the breaking change bubbles up through the public API surface to cause compilation +issues in your code. For example the signature for `IRequestBodyAsyncFilter.ApplyAsync()` has changed as shown below: + +```diff +- Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyAsyncFilter.ApplyAsync(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task ++ Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyAsyncFilter.ApplyAsync(Microsoft.OpenApi.IOpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +``` + +## Migration Overview + +Migrating to Swashbuckle.AspNetCore v10+ will likely involve changes in the following areas: + +- Update any NuGet package references for Swashbuckle.AspNetCore and Microsoft.OpenApi to v10+ and v2.x.x respectively. +- Update any `using` directives that reference types from the `Microsoft.OpenApi.Models` namespace to use the new namespace `Microsoft.OpenApi`. +- Update model references (e.g. `OpenApiSchema`) to use the new interfaces (e.g. `IOpenApiSchema`) and the relevant concrete types to mutate them (e.g. `OpenApiSchema`). +- Update any use of `.Reference` properties (e.g. `OpenApiSchema.ReferenceV3`) to use the new `*Reference` class instead (e.g. `OpenApiSchemaReference`). +- Replace usage of the `OpenApiSchema.Type` property using a string (e.g. `"string"` or `"boolean"`) with the `JsonSchemaType` flags enumeration. +- Replace usage of the `OpenApiSchema.Nullable` property by OR-ing the `JsonSchemaType.Null` value to `OpenApiSchema.Type` (e.g. `schema.Type |= JsonSchemaType.Null;`). +- Remove any use of the [now-deprecated `WithOpenApi()` extension method][withopenapi-deprecation] in Microsoft.AspNetCore.OpenApi. + +[breaking-changes-aspnetcore]: https://learn.microsoft.com/aspnet/core/release-notes/aspnetcore-10.0?#openapi-31-breaking-changes "OpenAPI 3.1 breaking changes" +[feature-request]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2349 "Plans on official support for OpenApi 3.1.0" +[microsoft-openapi-package]: https://www.nuget.org/packages/Microsoft.OpenApi/ "Microsoft.OpenApi NuGet package" +[microsoft-openapi-v2-migration-guide]: https://github.com/microsoft/OpenAPI.NET/blob/main/docs/upgrade-guide-2.md "Microsoft OpenAPI.NET v2 migration guide" +[openapi-specification]: https://swagger.io/specification/ "OpenAPI Specification" +[swashbuckle-aspnetcore-10]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/3283 "Support .NET 10" +[withopenapi-deprecation]: https://github.com/aspnet/Announcements/issues/519 "[Breaking change]: Deprecation of WithOpenApi extension method" diff --git a/global.json b/global.json index 909a1fb9ce..bcd874c697 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.306", + "version": "10.0.100-rc.2.25502.107", "allowPrerelease": false, "rollForward": "latestMajor", "paths": [ ".dotnet", "$host$" ] diff --git a/perf/Swashbuckle.AspNetCore.Benchmarks/Swashbuckle.AspNetCore.Benchmarks.csproj b/perf/Swashbuckle.AspNetCore.Benchmarks/Swashbuckle.AspNetCore.Benchmarks.csproj index 718d1dfc14..b876a81442 100644 --- a/perf/Swashbuckle.AspNetCore.Benchmarks/Swashbuckle.AspNetCore.Benchmarks.csproj +++ b/perf/Swashbuckle.AspNetCore.Benchmarks/Swashbuckle.AspNetCore.Benchmarks.csproj @@ -2,7 +2,7 @@ false Exe - net9.0 + net10.0 True $(MSBuildThisFileDirectory)..\..\src\Swashbuckle.AspNetCore.Swagger\Swashbuckle.AspNetCore.Swagger.snk diff --git a/perf/Swashbuckle.AspNetCore.Benchmarks/XmlCommentsBenchmark.cs b/perf/Swashbuckle.AspNetCore.Benchmarks/XmlCommentsBenchmark.cs index f50fe1f485..ccdb2cbb76 100644 --- a/perf/Swashbuckle.AspNetCore.Benchmarks/XmlCommentsBenchmark.cs +++ b/perf/Swashbuckle.AspNetCore.Benchmarks/XmlCommentsBenchmark.cs @@ -4,7 +4,7 @@ using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen.Test; using Swashbuckle.AspNetCore.TestSupport; @@ -57,7 +57,9 @@ public void Setup() using var xmlStream = new MemoryStream(); xmlDocument.Save(xmlStream); xmlStream.Seek(0, SeekOrigin.Begin); + var xPathDocument = new XPathDocument(xmlStream); + var members = XmlCommentsDocumentHelper.CreateMemberDictionary(xPathDocument); // Document _document = new OpenApiDocument(); @@ -83,7 +85,7 @@ public void Setup() null, null); - _documentFilter = new XmlCommentsDocumentFilter(xPathDocument); + _documentFilter = new XmlCommentsDocumentFilter(members, new()); // Operation _operation = new OpenApiOperation(); @@ -91,13 +93,13 @@ public void Setup() .GetMethod(nameof(FakeConstructedControllerWithXmlComments.ActionWithSummaryAndResponseTags)); var apiDescription = ApiDescriptionFactory.Create(methodInfo: methodInfo, groupName: "v1", httpMethod: "POST", relativePath: "resource"); - _operationFilterContext = new OperationFilterContext(apiDescription, null, null, methodInfo); - _operationFilter = new XmlCommentsOperationFilter(xPathDocument); + _operationFilterContext = new OperationFilterContext(apiDescription, null, null, null, methodInfo); + _operationFilter = new XmlCommentsOperationFilter(members, new()); // Parameter _parameter = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaTypes.String, Description = "schema-level description", @@ -106,8 +108,9 @@ public void Setup() var propertyInfo = typeof(XmlAnnotatedType).GetProperty(nameof(XmlAnnotatedType.StringProperty)); var apiParameterDescription = new ApiParameterDescription(); - _parameterFilterContext = new ParameterFilterContext(apiParameterDescription, null, null, propertyInfo: propertyInfo); - _parameterFilter = new XmlCommentsParameterFilter(xPathDocument); + var xmlDocMembers = XmlCommentsDocumentHelper.CreateMemberDictionary(xPathDocument); + _parameterFilterContext = new ParameterFilterContext(apiParameterDescription, null, null, null, propertyInfo: propertyInfo); + _parameterFilter = new XmlCommentsParameterFilter(xmlDocMembers, new()); // Request Body _requestBody = new OpenApiRequestBody @@ -116,7 +119,7 @@ public void Setup() { ["application/json"] = new() { - Schema = new() + Schema = new OpenApiSchema() { Type = JsonSchemaTypes.String, }, @@ -131,8 +134,8 @@ public void Setup() { ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo } }; - _requestBodyFilterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); - _requestBodyFilter = new XmlCommentsRequestBodyFilter(xPathDocument); + _requestBodyFilterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); + _requestBodyFilter = new XmlCommentsRequestBodyFilter(xmlDocMembers, new()); } [Benchmark] diff --git a/src/Shared/JsonExtensions.cs b/src/Shared/JsonExtensions.cs new file mode 100644 index 0000000000..cd314a1f5e --- /dev/null +++ b/src/Shared/JsonExtensions.cs @@ -0,0 +1,26 @@ +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace Swashbuckle.AspNetCore; + +internal static class JsonExtensions +{ + private static readonly JsonSerializerOptions Options = new() + { +#if NET9_0_OR_GREATER + NewLine = "\n", +#endif + WriteIndented = true, + }; + + public static string ToJson(this JsonNode value) + { + var json = value.ToJsonString(Options); + +#if !NET9_0_OR_GREATER + json = json.Replace("\r\n", "\n"); +#endif + + return json; + } +} diff --git a/src/Shared/JsonSchemaTypes.cs b/src/Shared/JsonSchemaTypes.cs index 7285f9e9e1..693640ceca 100644 --- a/src/Shared/JsonSchemaTypes.cs +++ b/src/Shared/JsonSchemaTypes.cs @@ -1,12 +1,14 @@ +using Microsoft.OpenApi; + namespace Swashbuckle.AspNetCore; internal static class JsonSchemaTypes { - public const string Array = "array"; - public const string Boolean = "boolean"; - public const string Integer = "integer"; - public const string Number = "number"; - public const string Null = "null"; - public const string Object = "object"; - public const string String = "string"; + public static readonly JsonSchemaType Array = JsonSchemaType.Array; + public static readonly JsonSchemaType Boolean = JsonSchemaType.Boolean; + public static readonly JsonSchemaType Integer = JsonSchemaType.Integer; + public static readonly JsonSchemaType Number = JsonSchemaType.Number; + public static readonly JsonSchemaType Null = JsonSchemaType.Null; + public static readonly JsonSchemaType Object = JsonSchemaType.Object; + public static readonly JsonSchemaType String = JsonSchemaType.String; } diff --git a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsDocumentFilter.cs b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsDocumentFilter.cs index a54ed0e838..412780804c 100644 --- a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsDocumentFilter.cs +++ b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsDocumentFilter.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Annotations; @@ -8,7 +8,7 @@ public class AnnotationsDocumentFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { - swaggerDoc.Tags ??= []; + swaggerDoc.Tags ??= new SortedSet(); // Collect (unique) controller names and custom attributes in a dictionary var controllerNamesAndAttributes = context.ApiDescriptions @@ -24,7 +24,7 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) } private static void ApplySwaggerTagAttribute( - OpenApiDocument swaggerDoc, + OpenApiDocument document, string controllerName, IEnumerable customAttributes) { @@ -32,18 +32,24 @@ private static void ApplySwaggerTagAttribute( .OfType() .FirstOrDefault(); - if (swaggerTagAttribute == null) + if (swaggerTagAttribute is null) { return; } - swaggerDoc.Tags.Add(new OpenApiTag + var tag = document.Tags.FirstOrDefault((p) => p?.Name == controllerName); + + if (tag is null) + { + tag = new() { Name = controllerName }; + document.Tags.Add(tag); + } + + tag.Description ??= swaggerTagAttribute.Description; + + if (swaggerTagAttribute.ExternalDocsUrl is { } url) { - Name = controllerName, - Description = swaggerTagAttribute.Description, - ExternalDocs = (swaggerTagAttribute.ExternalDocsUrl != null) - ? new OpenApiExternalDocs { Url = new Uri(swaggerTagAttribute.ExternalDocsUrl) } - : null - }); + tag.ExternalDocs ??= new OpenApiExternalDocs { Url = new(url) }; + } } } diff --git a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsOperationFilter.cs b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsOperationFilter.cs index e19c077520..25c960fccc 100644 --- a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsOperationFilter.cs +++ b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsOperationFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Annotations; @@ -69,7 +69,7 @@ private static void ApplySwaggerOperationAttribute( if (swaggerOperationAttribute.Tags is { } tags) { - operation.Tags = [.. tags.Select(tagName => new OpenApiTag { Name = tagName })]; + operation.Tags = new SortedSet(tags.Select(tagName => new OpenApiTagReference(tagName))); } } @@ -113,9 +113,11 @@ private static void ApplySwaggerResponseAttributes( operation.Responses[statusCode] = response; - if (swaggerResponseAttribute.ContentTypes is { } contentTypes) + if (response is OpenApiResponse concrete && + swaggerResponseAttribute.ContentTypes is { } contentTypes) { - response.Content.Clear(); + concrete.Content?.Clear(); + concrete.Content ??= new Dictionary(); foreach (var contentType in contentTypes) { @@ -123,7 +125,7 @@ private static void ApplySwaggerResponseAttributes( ? context.SchemaGenerator.GenerateSchema(swaggerResponseAttribute.Type, context.SchemaRepository) : null; - response.Content.Add(contentType, new OpenApiMediaType { Schema = schema }); + concrete.Content.Add(contentType, new OpenApiMediaType { Schema = schema }); } } } diff --git a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsParameterFilter.cs b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsParameterFilter.cs index 446dd1d90b..cdb1712a3c 100644 --- a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsParameterFilter.cs +++ b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsParameterFilter.cs @@ -1,24 +1,25 @@ using System.Reflection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Annotations; public class AnnotationsParameterFilter : IParameterFilter { - public void Apply(OpenApiParameter parameter, ParameterFilterContext context) + public void Apply(IOpenApiParameter parameter, ParameterFilterContext context) { - if (context.PropertyInfo != null) + if (context.PropertyInfo is { } propertyInfo) { - ApplyPropertyAnnotations(parameter, context.PropertyInfo); + ApplyPropertyAnnotations(parameter, propertyInfo); } - else if (context.ParameterInfo != null) + + if (context.ParameterInfo is { } parameterInfo) { - ApplyParamAnnotations(parameter, context.ParameterInfo); + ApplyParamAnnotations(parameter, parameterInfo); } } - private static void ApplyPropertyAnnotations(OpenApiParameter parameter, PropertyInfo propertyInfo) + private static void ApplyPropertyAnnotations(IOpenApiParameter parameter, PropertyInfo propertyInfo) { var swaggerParameterAttribute = propertyInfo.GetCustomAttributes() .FirstOrDefault(); @@ -29,7 +30,7 @@ private static void ApplyPropertyAnnotations(OpenApiParameter parameter, Propert } } - private static void ApplyParamAnnotations(OpenApiParameter parameter, ParameterInfo parameterInfo) + private static void ApplyParamAnnotations(IOpenApiParameter parameter, ParameterInfo parameterInfo) { var swaggerParameterAttribute = parameterInfo.GetCustomAttribute(); @@ -39,7 +40,7 @@ private static void ApplyParamAnnotations(OpenApiParameter parameter, ParameterI } } - private static void ApplySwaggerParameterAttribute(OpenApiParameter parameter, SwaggerParameterAttribute swaggerParameterAttribute) + private static void ApplySwaggerParameterAttribute(IOpenApiParameter parameter, SwaggerParameterAttribute swaggerParameterAttribute) { if (swaggerParameterAttribute.Description is { } description) { diff --git a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsRequestBodyFilter.cs b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsRequestBodyFilter.cs index 38c846ccd0..7cc7a61352 100644 --- a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsRequestBodyFilter.cs +++ b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsRequestBodyFilter.cs @@ -1,12 +1,12 @@ using System.Reflection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Annotations; public class AnnotationsRequestBodyFilter : IRequestBodyFilter { - public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context) + public void Apply(IOpenApiRequestBody requestBody, RequestBodyFilterContext context) { var bodyParameterDescription = context.BodyParameterDescription; @@ -19,18 +19,16 @@ public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext conte if (propertyInfo != null) { ApplyPropertyAnnotations(requestBody, propertyInfo); - return; } var parameterInfo = bodyParameterDescription.ParameterInfo(); if (parameterInfo != null) { ApplyParamAnnotations(requestBody, parameterInfo); - return; } } - private static void ApplyPropertyAnnotations(OpenApiRequestBody parameter, PropertyInfo propertyInfo) + private static void ApplyPropertyAnnotations(IOpenApiRequestBody parameter, PropertyInfo propertyInfo) { var swaggerRequestBodyAttribute = propertyInfo.GetCustomAttributes() .FirstOrDefault(); @@ -41,7 +39,7 @@ private static void ApplyPropertyAnnotations(OpenApiRequestBody parameter, Prope } } - private static void ApplyParamAnnotations(OpenApiRequestBody requestBody, ParameterInfo parameterInfo) + private static void ApplyParamAnnotations(IOpenApiRequestBody requestBody, ParameterInfo parameterInfo) { var swaggerRequestBodyAttribute = parameterInfo.GetCustomAttribute(); @@ -51,7 +49,7 @@ private static void ApplyParamAnnotations(OpenApiRequestBody requestBody, Parame } } - private static void ApplySwaggerRequestBodyAttribute(OpenApiRequestBody parameter, SwaggerRequestBodyAttribute swaggerRequestBodyAttribute) + private static void ApplySwaggerRequestBodyAttribute(IOpenApiRequestBody parameter, SwaggerRequestBodyAttribute swaggerRequestBodyAttribute) { if (swaggerRequestBodyAttribute.Description is { } description) { diff --git a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsSchemaFilter.cs b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsSchemaFilter.cs index ae0829161b..58fcd2c90f 100644 --- a/src/Swashbuckle.AspNetCore.Annotations/AnnotationsSchemaFilter.cs +++ b/src/Swashbuckle.AspNetCore.Annotations/AnnotationsSchemaFilter.cs @@ -1,6 +1,6 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Annotations; @@ -9,7 +9,7 @@ public class AnnotationsSchemaFilter(IServiceProvider serviceProvider) : ISchema { private readonly IServiceProvider _serviceProvider = serviceProvider; - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { ApplyTypeAnnotations(schema, context); @@ -26,7 +26,7 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context) } } - private void ApplyTypeAnnotations(OpenApiSchema schema, SchemaFilterContext context) + private void ApplyTypeAnnotations(IOpenApiSchema schema, SchemaFilterContext context) { var schemaAttribute = context.Type.GetCustomAttributes() .FirstOrDefault(); @@ -50,7 +50,7 @@ private void ApplyTypeAnnotations(OpenApiSchema schema, SchemaFilterContext cont } } - private static void ApplyParamAnnotations(OpenApiSchema schema, ParameterInfo parameterInfo) + private static void ApplyParamAnnotations(IOpenApiSchema schema, ParameterInfo parameterInfo) { var schemaAttribute = parameterInfo.GetCustomAttributes() .FirstOrDefault(); @@ -61,7 +61,7 @@ private static void ApplyParamAnnotations(OpenApiSchema schema, ParameterInfo pa } } - private static void ApplyMemberAnnotations(OpenApiSchema schema, MemberInfo memberInfo) + private static void ApplyMemberAnnotations(IOpenApiSchema schema, MemberInfo memberInfo) { var schemaAttribute = memberInfo.GetCustomAttributes() .FirstOrDefault(); @@ -72,41 +72,55 @@ private static void ApplyMemberAnnotations(OpenApiSchema schema, MemberInfo memb } } - private static void ApplySchemaAttribute(OpenApiSchema schema, SwaggerSchemaAttribute schemaAttribute) + private static void ApplySchemaAttribute(IOpenApiSchema schema, SwaggerSchemaAttribute schemaAttribute) { if (schemaAttribute.Description is { } description) { schema.Description = description; } + if (schema is not OpenApiSchema concrete) + { + return; + } + if (schemaAttribute.Format is { } format) { - schema.Format = format; + concrete.Format = format; } if (schemaAttribute.ReadOnlyFlag is { } readOnly) { - schema.ReadOnly = readOnly; + concrete.ReadOnly = readOnly; } if (schemaAttribute.WriteOnlyFlag is { } writeOnly) { - schema.WriteOnly = writeOnly; + concrete.WriteOnly = writeOnly; } if (schemaAttribute.NullableFlag is { } nullable) { - schema.Nullable = nullable; + // See https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/3387 + if (nullable) + { + concrete.Type ??= JsonSchemaType.Null; + concrete.Type |= JsonSchemaType.Null; + } + else if (concrete.Type.HasValue) + { + concrete.Type &= ~JsonSchemaType.Null; + } } if (schemaAttribute.Required is { } required) { - schema.Required = new SortedSet(required); + concrete.Required = new SortedSet(required); } if (schemaAttribute.Title is { } title) { - schema.Title = title; + concrete.Title = title; } } } diff --git a/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Shipped.txt b/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Shipped.txt index 1988ce538e..95e1451167 100644 --- a/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Shipped.txt @@ -1,22 +1,16 @@ Microsoft.Extensions.DependencyInjection.AnnotationsSwaggerGenOptionsExtensions static Microsoft.Extensions.DependencyInjection.AnnotationsSwaggerGenOptionsExtensions.EnableAnnotations(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions options) -> void static Microsoft.Extensions.DependencyInjection.AnnotationsSwaggerGenOptionsExtensions.EnableAnnotations(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions options, bool enableAnnotationsForInheritance, bool enableAnnotationsForPolymorphism) -> void -static Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter.ApplySwaggerOperationFilterAttributes(Microsoft.OpenApi.Models.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context, System.Collections.Generic.IEnumerable controllerAndActionAttributes) -> void Swashbuckle.AspNetCore.Annotations.AnnotationsDocumentFilter Swashbuckle.AspNetCore.Annotations.AnnotationsDocumentFilter.AnnotationsDocumentFilter() -> void -Swashbuckle.AspNetCore.Annotations.AnnotationsDocumentFilter.Apply(Microsoft.OpenApi.Models.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context) -> void Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter.AnnotationsOperationFilter() -> void -Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter.Apply(Microsoft.OpenApi.Models.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context) -> void Swashbuckle.AspNetCore.Annotations.AnnotationsParameterFilter Swashbuckle.AspNetCore.Annotations.AnnotationsParameterFilter.AnnotationsParameterFilter() -> void -Swashbuckle.AspNetCore.Annotations.AnnotationsParameterFilter.Apply(Microsoft.OpenApi.Models.OpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context) -> void Swashbuckle.AspNetCore.Annotations.AnnotationsRequestBodyFilter Swashbuckle.AspNetCore.Annotations.AnnotationsRequestBodyFilter.AnnotationsRequestBodyFilter() -> void -Swashbuckle.AspNetCore.Annotations.AnnotationsRequestBodyFilter.Apply(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context) -> void Swashbuckle.AspNetCore.Annotations.AnnotationsSchemaFilter Swashbuckle.AspNetCore.Annotations.AnnotationsSchemaFilter.AnnotationsSchemaFilter(System.IServiceProvider serviceProvider) -> void -Swashbuckle.AspNetCore.Annotations.AnnotationsSchemaFilter.Apply(Microsoft.OpenApi.Models.OpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext context) -> void Swashbuckle.AspNetCore.Annotations.SwaggerDiscriminatorAttribute Swashbuckle.AspNetCore.Annotations.SwaggerDiscriminatorAttribute.PropertyName.get -> string Swashbuckle.AspNetCore.Annotations.SwaggerDiscriminatorAttribute.PropertyName.set -> void diff --git a/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Unshipped.txt b/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Unshipped.txt index e69de29bb2..72edd514e5 100644 --- a/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Swashbuckle.AspNetCore.Annotations/PublicAPI/PublicAPI.Unshipped.txt @@ -0,0 +1,6 @@ +static Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter.ApplySwaggerOperationFilterAttributes(Microsoft.OpenApi.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context, System.Collections.Generic.IEnumerable controllerAndActionAttributes) -> void +Swashbuckle.AspNetCore.Annotations.AnnotationsDocumentFilter.Apply(Microsoft.OpenApi.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context) -> void +Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter.Apply(Microsoft.OpenApi.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context) -> void +Swashbuckle.AspNetCore.Annotations.AnnotationsParameterFilter.Apply(Microsoft.OpenApi.IOpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context) -> void +Swashbuckle.AspNetCore.Annotations.AnnotationsRequestBodyFilter.Apply(Microsoft.OpenApi.IOpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context) -> void +Swashbuckle.AspNetCore.Annotations.AnnotationsSchemaFilter.Apply(Microsoft.OpenApi.IOpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext context) -> void diff --git a/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/ApiTestFixture.cs b/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/ApiTestFixture.cs index b3f31dc22b..4441d637fb 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/ApiTestFixture.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/ApiTestFixture.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Xunit; namespace Swashbuckle.AspNetCore.ApiTesting.Xunit; @@ -15,7 +15,7 @@ public class ApiTestFixture( private readonly WebApplicationFactory _webAppFactory = webAppFactory; private readonly string _documentName = documentName; - public void Describe(string pathTemplate, OperationType operationType, OpenApiOperation operationSpec) + public void Describe(string pathTemplate, HttpMethod operationType, OpenApiOperation operationSpec) { _apiTestRunner.ConfigureOperation(_documentName, pathTemplate, operationType, operationSpec); } diff --git a/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Shipped.txt b/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Shipped.txt index 3b608f0e78..c36b8bf81c 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Shipped.txt @@ -1,4 +1,3 @@ Swashbuckle.AspNetCore.ApiTesting.Xunit.ApiTestFixture Swashbuckle.AspNetCore.ApiTesting.Xunit.ApiTestFixture.ApiTestFixture(Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase apiTestRunner, Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory webAppFactory, string documentName) -> void -Swashbuckle.AspNetCore.ApiTesting.Xunit.ApiTestFixture.Describe(string pathTemplate, Microsoft.OpenApi.Models.OperationType operationType, Microsoft.OpenApi.Models.OpenApiOperation operationSpec) -> void Swashbuckle.AspNetCore.ApiTesting.Xunit.ApiTestFixture.TestAsync(string operationId, string expectedStatusCode, System.Net.Http.HttpRequestMessage request) -> System.Threading.Tasks.Task diff --git a/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Unshipped.txt b/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Unshipped.txt index e69de29bb2..4b3b9b0954 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Swashbuckle.AspNetCore.ApiTesting.Xunit/PublicAPI/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +Swashbuckle.AspNetCore.ApiTesting.Xunit.ApiTestFixture.Describe(string pathTemplate, System.Net.Http.HttpMethod operationType, Microsoft.OpenApi.OpenApiOperation operationSpec) -> void diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerBase.cs b/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerBase.cs index 44580fea53..cd6b23a3de 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerBase.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerBase.cs @@ -1,5 +1,4 @@ -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; @@ -24,7 +23,7 @@ public void Configure(Action setupAction) public void ConfigureOperation( string documentName, string pathTemplate, - OperationType operationType, + HttpMethod operationType, OpenApiOperation operation) { var openApiDocument = _options.GetOpenApiDocument(documentName); diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptions.cs b/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptions.cs index 0aaad418f2..8ec809aa19 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptions.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptions.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptionsExtensions.cs b/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptionsExtensions.cs index d99c6dce55..15a148ec20 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptionsExtensions.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/ApiTestRunnerOptionsExtensions.cs @@ -1,5 +1,4 @@ -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Readers; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; @@ -8,9 +7,13 @@ public static class ApiTestRunnerOptionsExtensions public static void AddOpenApiFile(this ApiTestRunnerOptions options, string documentName, string filePath) { using var fileStream = File.OpenRead(filePath); + using var memoryStream = new MemoryStream(); - var openApiDocument = new OpenApiStreamReader().Read(fileStream, out var diagnostic); - options.OpenApiDocs.Add(documentName, openApiDocument); + fileStream.CopyTo(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + + var result = OpenApiDocument.Load(memoryStream); + options.OpenApiDocs.Add(documentName, result.Document); } public static OpenApiDocument GetOpenApiDocument(this ApiTestRunnerOptions options, string documentName) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/IContentValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/IContentValidator.cs index 220270962b..6cd0e20cc1 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/IContentValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/IContentValidator.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonContentValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonContentValidator.cs index 34f8af5a02..c850e528ab 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonContentValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonContentValidator.cs @@ -1,9 +1,9 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonContentValidator : IContentValidator +public sealed class JsonContentValidator : IContentValidator { private readonly JsonValidator _jsonValidator = new(); diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/IJsonValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/IJsonValidator.cs index 22874ec0d3..15b08c8e5f 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/IJsonValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/IJsonValidator.cs @@ -1,14 +1,14 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; public interface IJsonValidator { - bool CanValidate(OpenApiSchema schema); + bool CanValidate(IOpenApiSchema schema); bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages); diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAllOfValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAllOfValidator.cs index c9751582bd..3fb9b1d01e 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAllOfValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAllOfValidator.cs @@ -1,16 +1,16 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonAllOfValidator(JsonValidator jsonValidator) : IJsonValidator +public sealed class JsonAllOfValidator(JsonValidator jsonValidator) : IJsonValidator { private readonly JsonValidator _jsonValidator = jsonValidator; - public bool CanValidate(OpenApiSchema schema) => schema.AllOf != null && schema.AllOf.Any(); + public bool CanValidate(IOpenApiSchema schema) => schema.AllOf != null && schema.AllOf.Any(); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAnyOfValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAnyOfValidator.cs index 50e0d602b5..cccb037412 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAnyOfValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonAnyOfValidator.cs @@ -1,16 +1,16 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonAnyOfValidator(JsonValidator jsonValidator) : IJsonValidator +public sealed class JsonAnyOfValidator(JsonValidator jsonValidator) : IJsonValidator { private readonly JsonValidator _jsonValidator = jsonValidator; - public bool CanValidate(OpenApiSchema schema) => schema.AnyOf != null && schema.AnyOf.Any(); + public bool CanValidate(IOpenApiSchema schema) => schema.AnyOf != null && schema.AnyOf.Any(); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonArrayValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonArrayValidator.cs index c6d297014f..87e3241f84 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonArrayValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonArrayValidator.cs @@ -1,16 +1,16 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonArrayValidator(IJsonValidator jsonValidator) : IJsonValidator +public sealed class JsonArrayValidator(IJsonValidator jsonValidator) : IJsonValidator { private readonly IJsonValidator _jsonValidator = jsonValidator; - public bool CanValidate(OpenApiSchema schema) => schema.Type == JsonSchemaTypes.Array; + public bool CanValidate(IOpenApiSchema schema) => schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Array); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonBooleanValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonBooleanValidator.cs index 9e06b42ac3..4e40b5b894 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonBooleanValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonBooleanValidator.cs @@ -1,14 +1,14 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonBooleanValidator : IJsonValidator +public sealed class JsonBooleanValidator : IJsonValidator { - public bool CanValidate(OpenApiSchema schema) => schema.Type == JsonSchemaTypes.Boolean; + public bool CanValidate(IOpenApiSchema schema) => schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Boolean); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNullValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNullValidator.cs index 8ddf15b53c..fb54f41150 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNullValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNullValidator.cs @@ -1,14 +1,14 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonNullValidator : IJsonValidator +public sealed class JsonNullValidator : IJsonValidator { - public bool CanValidate(OpenApiSchema schema) => schema.Type == JsonSchemaTypes.Null; + public bool CanValidate(IOpenApiSchema schema) => schema.Type == JsonSchemaTypes.Null; public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNumberValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNumberValidator.cs index 99cafbd2a2..8bb2112cf2 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNumberValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonNumberValidator.cs @@ -1,14 +1,14 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonNumberValidator : IJsonValidator +public sealed class JsonNumberValidator : IJsonValidator { - public bool CanValidate(OpenApiSchema schema) => schema.Type == JsonSchemaTypes.Number; + public bool CanValidate(IOpenApiSchema schema) => schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Number); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) @@ -23,39 +23,37 @@ public bool Validate( var errors = new List(); // multipleOf - if (schema.MultipleOf.HasValue && ((numberValue % schema.MultipleOf.Value) != 0)) + if (schema.MultipleOf is { } multipleOf && (numberValue % multipleOf) != 0) { errors.Add($"Path: {instance.Path}. Number is not evenly divisible by multipleOf"); } - // maximum & exclusiveMaximum - if (schema.Maximum.HasValue) + if (schema.ExclusiveMaximum is { } exclusiveMaximum && + decimal.TryParse(exclusiveMaximum, out var exclusiveMaximumValue) && + numberValue >= exclusiveMaximumValue) { - var exclusiveMaximum = schema.ExclusiveMaximum ?? false; + errors.Add($"Path: {instance.Path}. Number is greater than, or equal to, maximum"); + } - if (exclusiveMaximum && (numberValue >= schema.Maximum.Value)) - { - errors.Add($"Path: {instance.Path}. Number is greater than, or equal to, maximum"); - } - else if (numberValue > schema.Maximum.Value) - { - errors.Add($"Path: {instance.Path}. Number is greater than maximum"); - } + if (schema.Maximum is { } maximum && + decimal.TryParse(maximum, out var maximumValue) && + numberValue > maximumValue) + { + errors.Add($"Path: {instance.Path}. Number is greater than maximum"); } - // minimum & exclusiveMinimum - if (schema.Minimum.HasValue) + if (schema.ExclusiveMinimum is { } exclusiveMinimum && + decimal.TryParse(exclusiveMinimum, out var exclusiveMinimumValue) && + numberValue <= exclusiveMinimumValue) { - var exclusiveMinimum = schema.ExclusiveMinimum ?? false; + errors.Add($"Path: {instance.Path}. Number is less than, or equal to, minimum"); + } - if (exclusiveMinimum && (numberValue <= schema.Minimum.Value)) - { - errors.Add($"Path: {instance.Path}. Number is less than, or equal to, minimum"); - } - else if (numberValue < schema.Minimum.Value) - { - errors.Add($"Path: {instance.Path}. Number is less than minimum"); - } + if (schema.Minimum is { } minimum && + decimal.TryParse(minimum, out var minimumValue) && + numberValue < minimumValue) + { + errors.Add($"Path: {instance.Path}. Number is less than minimum"); } errorMessages = errors; diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonObjectValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonObjectValidator.cs index 27b4cfd07b..d573af0d25 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonObjectValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonObjectValidator.cs @@ -1,16 +1,16 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonObjectValidator(IJsonValidator jsonValidator) : IJsonValidator +public sealed class JsonObjectValidator(IJsonValidator jsonValidator) : IJsonValidator { private readonly IJsonValidator _jsonValidator = jsonValidator; - public bool CanValidate(OpenApiSchema schema) => schema.Type == JsonSchemaTypes.Object; + public bool CanValidate(IOpenApiSchema schema) => schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Object); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonOneOfValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonOneOfValidator.cs index cb3b449e9a..8179675ccb 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonOneOfValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonOneOfValidator.cs @@ -1,16 +1,16 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonOneOfValidator(JsonValidator jsonValidator) : IJsonValidator +public sealed class JsonOneOfValidator(JsonValidator jsonValidator) : IJsonValidator { private readonly JsonValidator _jsonValidator = jsonValidator; - public bool CanValidate(OpenApiSchema schema) => schema.OneOf != null && schema.OneOf.Any(); + public bool CanValidate(IOpenApiSchema schema) => schema.OneOf != null && schema.OneOf.Any(); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonStringValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonStringValidator.cs index 48bb18bdca..bf4ff79db6 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonStringValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonStringValidator.cs @@ -1,15 +1,15 @@ using System.Text.RegularExpressions; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonStringValidator : IJsonValidator +public sealed class JsonStringValidator : IJsonValidator { - public bool CanValidate(OpenApiSchema schema) => schema.Type == JsonSchemaTypes.String; + public bool CanValidate(IOpenApiSchema schema) => schema.Type is { } type && type.HasFlag(JsonSchemaTypes.String); public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonValidator.cs index 553a77c9d4..3f15d42025 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/JsonValidation/JsonValidator.cs @@ -1,9 +1,9 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; namespace Swashbuckle.AspNetCore.ApiTesting; -public class JsonValidator : IJsonValidator +public sealed class JsonValidator : IJsonValidator { private readonly IEnumerable _subValidators; @@ -23,17 +23,18 @@ public JsonValidator() ]; } - public bool CanValidate(OpenApiSchema schema) => true; + public bool CanValidate(IOpenApiSchema schema) => true; public bool Validate( - OpenApiSchema schema, + IOpenApiSchema schema, OpenApiDocument openApiDocument, JToken instance, out IEnumerable errorMessages) { - schema = schema.Reference != null - ? (OpenApiSchema)openApiDocument.ResolveReference(schema.Reference) - : schema; + if (schema is OpenApiSchemaReference reference && !openApiDocument.Components.Schemas.Any((p) => p.Key == reference.Reference.Id)) + { + throw new InvalidOperationException($"Invalid Reference identifier '{reference.Reference.Id}'."); + } var errors = new List(); diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiDocumentExtensions.cs b/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiDocumentExtensions.cs index caaa119b35..b7173b6038 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiDocumentExtensions.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiDocumentExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; @@ -8,19 +8,25 @@ internal static bool TryFindOperationById( this OpenApiDocument openApiDocument, string operationId, out string pathTemplate, - out OperationType operationType) + out HttpMethod operationType) { - foreach (var pathEntry in openApiDocument.Paths ?? []) + if (openApiDocument.Paths is { Count: > 0 } paths) { - var pathItem = pathEntry.Value; - - foreach (var operationEntry in pathItem.Operations) + foreach (var pathEntry in paths) { - if (operationEntry.Value.OperationId == operationId) + var pathItem = pathEntry.Value; + + if (pathItem.Operations is { Count: > 0 } operations) { - pathTemplate = pathEntry.Key; - operationType = operationEntry.Key; - return true; + foreach (var operation in operations) + { + if (operation.Value.OperationId == operationId) + { + pathTemplate = pathEntry.Key; + operationType = operation.Key; + return true; + } + } } } } @@ -33,8 +39,8 @@ internal static bool TryFindOperationById( internal static OpenApiOperation GetOperationByPathAndType( this OpenApiDocument openApiDocument, string pathTemplate, - OperationType operationType, - out OpenApiPathItem pathSpec) + HttpMethod operationType, + out IOpenApiPathItem pathSpec) { if (openApiDocument.Paths.TryGetValue(pathTemplate, out pathSpec)) { diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiSchemaExtensions.cs b/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiSchemaExtensions.cs index 55c1e724a1..ba8067b2dc 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiSchemaExtensions.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/OpenApiSchemaExtensions.cs @@ -1,55 +1,55 @@ using System.Text; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; -public static class OpenApiSchemaExtensions +internal static class OpenApiSchemaExtensions { internal static bool TryParse(this OpenApiSchema schema, string stringValue, out object typedValue) { typedValue = null; - if (schema.Type == JsonSchemaTypes.Integer && schema.Format == "int64" && long.TryParse(stringValue, out long longValue)) + if (IsType(schema.Type, JsonSchemaTypes.Integer) && schema.Format == "int64" && long.TryParse(stringValue, out long longValue)) { typedValue = longValue; } - else if (schema.Type == JsonSchemaTypes.Integer && int.TryParse(stringValue, out int intValue)) + else if (IsType(schema.Type, JsonSchemaTypes.Integer) && int.TryParse(stringValue, out int intValue)) { typedValue = intValue; } - else if (schema.Type == JsonSchemaTypes.Number && schema.Format == "double" && double.TryParse(stringValue, out double doubleValue)) + else if (IsType(schema.Type, JsonSchemaTypes.Number) && schema.Format == "double" && double.TryParse(stringValue, out double doubleValue)) { typedValue = doubleValue; } - else if (schema.Type == JsonSchemaTypes.Number && float.TryParse(stringValue, out float floatValue)) + else if (IsType(schema.Type, JsonSchemaTypes.Number) && float.TryParse(stringValue, out float floatValue)) { typedValue = floatValue; } - else if (schema.Type == JsonSchemaTypes.String && schema.Format == "byte" && byte.TryParse(stringValue, out byte byteValue)) + else if (IsType(schema.Type, JsonSchemaTypes.String) && schema.Format == "byte" && byte.TryParse(stringValue, out byte byteValue)) { typedValue = byteValue; } - else if (schema.Type == JsonSchemaTypes.Boolean && bool.TryParse(stringValue, out bool boolValue)) + else if (IsType(schema.Type, JsonSchemaTypes.Boolean) && bool.TryParse(stringValue, out bool boolValue)) { typedValue = boolValue; } - else if (schema.Type == JsonSchemaTypes.String && schema.Format == "date" && DateTime.TryParse(stringValue, out DateTime dateValue)) + else if (IsType(schema.Type, JsonSchemaTypes.String) && schema.Format == "date" && DateTime.TryParse(stringValue, out DateTime dateValue)) { typedValue = dateValue; } - else if (schema.Type == JsonSchemaTypes.String && schema.Format == "date-time" && DateTime.TryParse(stringValue, out DateTime dateTimeValue)) + else if (IsType(schema.Type, JsonSchemaTypes.String) && schema.Format == "date-time" && DateTime.TryParse(stringValue, out DateTime dateTimeValue)) { typedValue = dateTimeValue; } - else if (schema.Type == JsonSchemaTypes.String && schema.Format == "uuid" && Guid.TryParse(stringValue, out Guid uuidValue)) + else if (IsType(schema.Type, JsonSchemaTypes.String) && schema.Format == "uuid" && Guid.TryParse(stringValue, out Guid uuidValue)) { typedValue = uuidValue; } - else if (schema.Type == JsonSchemaTypes.String) + else if (IsType(schema.Type, JsonSchemaTypes.String)) { typedValue = stringValue; } - else if (schema.Type == JsonSchemaTypes.Array) + else if (IsType(schema.Type, JsonSchemaTypes.Array)) { var arrayValue = schema.Items == null ? stringValue.Split(',') @@ -67,13 +67,16 @@ internal static bool TryParse(this OpenApiSchema schema, string stringValue, out } return typedValue != null; + + static bool IsType(JsonSchemaType? type, JsonSchemaType target) + => type is { } value && value.HasFlag(target); } internal static string TypeIdentifier(this OpenApiSchema schema) { var idBuilder = new StringBuilder(); - idBuilder.Append(schema.Type); + idBuilder.Append(schema.Type.ToString().ToLowerInvariant()); if (schema.Type == JsonSchemaTypes.Array && schema.Items != null) { diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Shipped.txt b/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Shipped.txt index 3494753fbe..476a5fce9e 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Shipped.txt @@ -1,10 +1,7 @@ static Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptionsExtensions.AddOpenApiFile(this Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions options, string documentName, string filePath) -> void -static Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptionsExtensions.GetOpenApiDocument(this Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions options, string documentName) -> Microsoft.OpenApi.Models.OpenApiDocument Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase.ApiTestRunnerBase() -> void Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase.Configure(System.Action setupAction) -> void -Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase.ConfigureOperation(string documentName, string pathTemplate, Microsoft.OpenApi.Models.OperationType operationType, Microsoft.OpenApi.Models.OpenApiOperation operation) -> void -Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase.Dispose() -> void Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase.TestAsync(string documentName, string operationId, string expectedStatusCode, System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpClient httpClient) -> System.Threading.Tasks.Task Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions.ApiTestRunnerOptions() -> void @@ -13,70 +10,43 @@ Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions.FileOutputRoot.get -> str Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions.FileOutputRoot.set -> void Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions.GenerateOpenApiFiles.get -> bool Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions.GenerateOpenApiFiles.set -> void -Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions.OpenApiDocs.get -> System.Collections.Generic.Dictionary Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptionsExtensions Swashbuckle.AspNetCore.ApiTesting.ContentDoesNotMatchSpecException Swashbuckle.AspNetCore.ApiTesting.ContentDoesNotMatchSpecException.ContentDoesNotMatchSpecException(string message) -> void Swashbuckle.AspNetCore.ApiTesting.HttpHeadersExtensions Swashbuckle.AspNetCore.ApiTesting.IContentValidator Swashbuckle.AspNetCore.ApiTesting.IContentValidator.CanValidate(string mediaType) -> bool -Swashbuckle.AspNetCore.ApiTesting.IContentValidator.Validate(Microsoft.OpenApi.Models.OpenApiMediaType mediaTypeSpec, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, System.Net.Http.HttpContent content) -> void Swashbuckle.AspNetCore.ApiTesting.IJsonValidator -Swashbuckle.AspNetCore.ApiTesting.IJsonValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool -Swashbuckle.AspNetCore.ApiTesting.IJsonValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonAllOfValidator -Swashbuckle.AspNetCore.ApiTesting.JsonAllOfValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonAllOfValidator.JsonAllOfValidator(Swashbuckle.AspNetCore.ApiTesting.JsonValidator jsonValidator) -> void -Swashbuckle.AspNetCore.ApiTesting.JsonAllOfValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonAnyOfValidator -Swashbuckle.AspNetCore.ApiTesting.JsonAnyOfValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonAnyOfValidator.JsonAnyOfValidator(Swashbuckle.AspNetCore.ApiTesting.JsonValidator jsonValidator) -> void -Swashbuckle.AspNetCore.ApiTesting.JsonAnyOfValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonArrayValidator -Swashbuckle.AspNetCore.ApiTesting.JsonArrayValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonArrayValidator.JsonArrayValidator(Swashbuckle.AspNetCore.ApiTesting.IJsonValidator jsonValidator) -> void -Swashbuckle.AspNetCore.ApiTesting.JsonArrayValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonBooleanValidator -Swashbuckle.AspNetCore.ApiTesting.JsonBooleanValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonBooleanValidator.JsonBooleanValidator() -> void -Swashbuckle.AspNetCore.ApiTesting.JsonBooleanValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonContentValidator Swashbuckle.AspNetCore.ApiTesting.JsonContentValidator.CanValidate(string mediaType) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonContentValidator.JsonContentValidator() -> void -Swashbuckle.AspNetCore.ApiTesting.JsonContentValidator.Validate(Microsoft.OpenApi.Models.OpenApiMediaType mediaTypeSpec, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, System.Net.Http.HttpContent content) -> void Swashbuckle.AspNetCore.ApiTesting.JsonNullValidator -Swashbuckle.AspNetCore.ApiTesting.JsonNullValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonNullValidator.JsonNullValidator() -> void -Swashbuckle.AspNetCore.ApiTesting.JsonNullValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonNumberValidator -Swashbuckle.AspNetCore.ApiTesting.JsonNumberValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonNumberValidator.JsonNumberValidator() -> void -Swashbuckle.AspNetCore.ApiTesting.JsonNumberValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonObjectValidator -Swashbuckle.AspNetCore.ApiTesting.JsonObjectValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonObjectValidator.JsonObjectValidator(Swashbuckle.AspNetCore.ApiTesting.IJsonValidator jsonValidator) -> void -Swashbuckle.AspNetCore.ApiTesting.JsonObjectValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonOneOfValidator -Swashbuckle.AspNetCore.ApiTesting.JsonOneOfValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonOneOfValidator.JsonOneOfValidator(Swashbuckle.AspNetCore.ApiTesting.JsonValidator jsonValidator) -> void -Swashbuckle.AspNetCore.ApiTesting.JsonOneOfValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonStringValidator -Swashbuckle.AspNetCore.ApiTesting.JsonStringValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonStringValidator.JsonStringValidator() -> void -Swashbuckle.AspNetCore.ApiTesting.JsonStringValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonValidator -Swashbuckle.AspNetCore.ApiTesting.JsonValidator.CanValidate(Microsoft.OpenApi.Models.OpenApiSchema schema) -> bool Swashbuckle.AspNetCore.ApiTesting.JsonValidator.JsonValidator() -> void -Swashbuckle.AspNetCore.ApiTesting.JsonValidator.Validate(Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool Swashbuckle.AspNetCore.ApiTesting.OpenApiDocumentExtensions -Swashbuckle.AspNetCore.ApiTesting.OpenApiSchemaExtensions Swashbuckle.AspNetCore.ApiTesting.RequestDoesNotMatchSpecException Swashbuckle.AspNetCore.ApiTesting.RequestDoesNotMatchSpecException.RequestDoesNotMatchSpecException(string message) -> void Swashbuckle.AspNetCore.ApiTesting.RequestValidator Swashbuckle.AspNetCore.ApiTesting.RequestValidator.RequestValidator(System.Collections.Generic.IEnumerable contentValidators) -> void -Swashbuckle.AspNetCore.ApiTesting.RequestValidator.Validate(System.Net.Http.HttpRequestMessage request, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, string pathTemplate, Microsoft.OpenApi.Models.OperationType operationType) -> void Swashbuckle.AspNetCore.ApiTesting.ResponseDoesNotMatchSpecException Swashbuckle.AspNetCore.ApiTesting.ResponseDoesNotMatchSpecException.ResponseDoesNotMatchSpecException(string message) -> void Swashbuckle.AspNetCore.ApiTesting.ResponseValidator Swashbuckle.AspNetCore.ApiTesting.ResponseValidator.ResponseValidator(System.Collections.Generic.IEnumerable contentValidators) -> void -Swashbuckle.AspNetCore.ApiTesting.ResponseValidator.Validate(System.Net.Http.HttpResponseMessage response, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, string pathTemplate, Microsoft.OpenApi.Models.OperationType operationType, string expectedStatusCode) -> void + diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Unshipped.txt b/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Unshipped.txt index e69de29bb2..2e5e2aa1a7 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Swashbuckle.AspNetCore.ApiTesting/PublicAPI/PublicAPI.Unshipped.txt @@ -0,0 +1,30 @@ +static Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptionsExtensions.GetOpenApiDocument(this Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions options, string documentName) -> Microsoft.OpenApi.OpenApiDocument +Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase.ConfigureOperation(string documentName, string pathTemplate, System.Net.Http.HttpMethod operationType, Microsoft.OpenApi.OpenApiOperation operation) -> void +Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerBase.Dispose() -> void +Swashbuckle.AspNetCore.ApiTesting.ApiTestRunnerOptions.OpenApiDocs.get -> System.Collections.Generic.Dictionary +Swashbuckle.AspNetCore.ApiTesting.IContentValidator.Validate(Microsoft.OpenApi.OpenApiMediaType mediaTypeSpec, Microsoft.OpenApi.OpenApiDocument openApiDocument, System.Net.Http.HttpContent content) -> void +Swashbuckle.AspNetCore.ApiTesting.IJsonValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.IJsonValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonAllOfValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonAllOfValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonAnyOfValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonAnyOfValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonArrayValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonArrayValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonBooleanValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonBooleanValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonContentValidator.Validate(Microsoft.OpenApi.OpenApiMediaType mediaTypeSpec, Microsoft.OpenApi.OpenApiDocument openApiDocument, System.Net.Http.HttpContent content) -> void +Swashbuckle.AspNetCore.ApiTesting.JsonNullValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonNullValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonNumberValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonNumberValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonObjectValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonObjectValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonOneOfValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonOneOfValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonStringValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonStringValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonValidator.CanValidate(Microsoft.OpenApi.IOpenApiSchema schema) -> bool +Swashbuckle.AspNetCore.ApiTesting.JsonValidator.Validate(Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.OpenApi.OpenApiDocument openApiDocument, Newtonsoft.Json.Linq.JToken instance, out System.Collections.Generic.IEnumerable errorMessages) -> bool +Swashbuckle.AspNetCore.ApiTesting.RequestValidator.Validate(System.Net.Http.HttpRequestMessage request, Microsoft.OpenApi.OpenApiDocument openApiDocument, string pathTemplate, System.Net.Http.HttpMethod operationType) -> void +Swashbuckle.AspNetCore.ApiTesting.ResponseValidator.Validate(System.Net.Http.HttpResponseMessage response, Microsoft.OpenApi.OpenApiDocument openApiDocument, string pathTemplate, System.Net.Http.HttpMethod operationType, string expectedStatusCode) -> void diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/RequestValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/RequestValidator.cs index d071761b0e..e557f15449 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/RequestValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/RequestValidator.cs @@ -3,11 +3,11 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Template; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; -public class RequestValidator(IEnumerable contentValidators) +public sealed class RequestValidator(IEnumerable contentValidators) { private readonly IEnumerable _contentValidators = contentValidators; @@ -15,10 +15,20 @@ public void Validate( HttpRequestMessage request, OpenApiDocument openApiDocument, string pathTemplate, - OperationType operationType) + HttpMethod operationType) { var operationSpec = openApiDocument.GetOperationByPathAndType(pathTemplate, operationType, out var pathSpec); - OpenApiParameter[] parameterSpecs = [.. pathSpec.Parameters, .. operationSpec.Parameters]; + IOpenApiParameter[] parameterSpecs = []; + + if (pathSpec.Parameters is { Count: > 0 } pathParameters) + { + parameterSpecs = [.. parameterSpecs, .. pathParameters]; + } + + if (operationSpec.Parameters is { Count: > 0 } operationParameters) + { + parameterSpecs = [.. parameterSpecs, .. operationParameters]; + } // Convert to absolute Uri as a workaround to limitation with Uri class - i.e. most of it's methods are not supported for relative Uri's. var requestUri = new Uri(new Uri("http://tempuri.org"), request.RequestUri); @@ -33,9 +43,9 @@ public void Validate( throw new RequestDoesNotMatchSpecException($"Request method '{request.Method}' does not match specified operation type '{operationType}'"); } - ValidateParameters(parameterSpecs.Where(p => p.In == ParameterLocation.Path), openApiDocument, pathNameValues); - ValidateParameters(parameterSpecs.Where(p => p.In == ParameterLocation.Query), openApiDocument, HttpUtility.ParseQueryString(requestUri.Query)); - ValidateParameters(parameterSpecs.Where(p => p.In == ParameterLocation.Header), openApiDocument, request.Headers.ToNameValueCollection()); + ValidateParameters(parameterSpecs.Where(p => p.In == ParameterLocation.Path), pathNameValues); + ValidateParameters(parameterSpecs.Where(p => p.In == ParameterLocation.Query), HttpUtility.ParseQueryString(requestUri.Query)); + ValidateParameters(parameterSpecs.Where(p => p.In == ParameterLocation.Header), request.Headers.ToNameValueCollection()); if (operationSpec.RequestBody != null) { @@ -64,8 +74,7 @@ private static bool TryParsePathNameValues(string pathTemplate, string requestUr private static void ValidateParameters( - IEnumerable parameterSpecs, - OpenApiDocument openApiDocument, + IEnumerable parameterSpecs, NameValueCollection parameterNameValues) { foreach (var parameterSpec in parameterSpecs) @@ -82,23 +91,15 @@ private static void ValidateParameters( continue; } - var schema = parameterSpec.Schema.Reference != null ? - (OpenApiSchema)openApiDocument.ResolveReference(parameterSpec.Schema.Reference) - : parameterSpec.Schema; - - if (!schema.TryParse(value, out object typedValue)) + if (parameterSpec.Schema is OpenApiSchema schema && !schema.TryParse(value, out object typedValue)) { - throw new RequestDoesNotMatchSpecException($"Parameter '{parameterSpec.Name}' is not of type '{parameterSpec.Schema.TypeIdentifier()}'"); + throw new RequestDoesNotMatchSpecException($"Parameter '{parameterSpec.Name}' is not of type '{schema.TypeIdentifier()}'"); } } } - private void ValidateContent(OpenApiRequestBody requestBodySpec, OpenApiDocument openApiDocument, HttpContent content) + private void ValidateContent(IOpenApiRequestBody requestBodySpec, OpenApiDocument openApiDocument, HttpContent content) { - requestBodySpec = requestBodySpec.Reference != null ? - (OpenApiRequestBody)openApiDocument.ResolveReference(requestBodySpec.Reference) - : requestBodySpec; - if (requestBodySpec.Required && content == null) { throw new RequestDoesNotMatchSpecException("Required content is not present"); diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/ResponseValidator.cs b/src/Swashbuckle.AspNetCore.ApiTesting/ResponseValidator.cs index 2232a0f30a..6954c352d6 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/ResponseValidator.cs +++ b/src/Swashbuckle.AspNetCore.ApiTesting/ResponseValidator.cs @@ -1,9 +1,9 @@ using System.Collections.Specialized; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.ApiTesting; -public class ResponseValidator(IEnumerable contentValidators) +public sealed class ResponseValidator(IEnumerable contentValidators) { private readonly IEnumerable _contentValidators = contentValidators; @@ -11,7 +11,7 @@ public void Validate( HttpResponseMessage response, OpenApiDocument openApiDocument, string pathTemplate, - OperationType operationType, + HttpMethod operationType, string expectedStatusCode) { var operationSpec = openApiDocument.GetOperationByPathAndType(pathTemplate, operationType, out _); @@ -26,7 +26,7 @@ public void Validate( throw new ResponseDoesNotMatchSpecException($"Status code '{statusCode}' does not match expected value '{expectedStatusCode}'"); } - ValidateHeaders(responseSpec.Headers, openApiDocument, response.Headers.ToNameValueCollection()); + ValidateHeaders(responseSpec.Headers, response.Headers.ToNameValueCollection()); if (responseSpec.Content != null && responseSpec.Content.Keys.Count != 0) { @@ -35,10 +35,14 @@ public void Validate( } private static void ValidateHeaders( - IDictionary headerSpecs, - OpenApiDocument openApiDocument, + IDictionary headerSpecs, NameValueCollection headerValues) { + if (headerSpecs is null) + { + return; + } + foreach (var entry in headerSpecs) { var value = headerValues[entry.Key]; @@ -54,18 +58,10 @@ private static void ValidateHeaders( continue; } - var schema = headerSpec.Schema.Reference != null ? - (OpenApiSchema)openApiDocument.ResolveReference(headerSpec.Schema.Reference) - : headerSpec.Schema; - - if (value == null) - { - continue; - } - - if (!schema.TryParse(value, out object typedValue)) + if (headerSpec.Schema is OpenApiSchema schema && + !schema.TryParse(value, out object typedValue)) { - throw new ResponseDoesNotMatchSpecException($"Header '{entry.Key}' is not of type '{headerSpec.Schema.TypeIdentifier()}'"); + throw new ResponseDoesNotMatchSpecException($"Header '{entry.Key}' is not of type '{schema.TypeIdentifier()}'"); } } } diff --git a/src/Swashbuckle.AspNetCore.ApiTesting/Swashbuckle.AspNetCore.ApiTesting.csproj b/src/Swashbuckle.AspNetCore.ApiTesting/Swashbuckle.AspNetCore.ApiTesting.csproj index 34cf0cd49d..02a568ad79 100644 --- a/src/Swashbuckle.AspNetCore.ApiTesting/Swashbuckle.AspNetCore.ApiTesting.csproj +++ b/src/Swashbuckle.AspNetCore.ApiTesting/Swashbuckle.AspNetCore.ApiTesting.csproj @@ -10,8 +10,7 @@ - - + @@ -23,6 +22,10 @@ + + + + diff --git a/src/Swashbuckle.AspNetCore.Cli/Program.cs b/src/Swashbuckle.AspNetCore.Cli/Program.cs index ceea11ceeb..14d65ac17a 100644 --- a/src/Swashbuckle.AspNetCore.Cli/Program.cs +++ b/src/Swashbuckle.AspNetCore.Cli/Program.cs @@ -8,7 +8,6 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using Microsoft.OpenApi; -using Microsoft.OpenApi.Writers; using Swashbuckle.AspNetCore.Swagger; namespace Swashbuckle.AspNetCore.Cli; @@ -105,6 +104,7 @@ public static int Main(string[] args) { "2.0" => OpenApiSpecVersion.OpenApi2_0, "3.0" => OpenApiSpecVersion.OpenApi3_0, + "3.1" => OpenApiSpecVersion.OpenApi3_1, _ => throw new NotSupportedException($"The specified OpenAPI version \"{versionArg}\" is not supported."), }; } @@ -115,17 +115,7 @@ public static int Main(string[] args) } else { - switch (specVersion) - { - case OpenApiSpecVersion.OpenApi2_0: - swagger.SerializeAsV2(writer); - break; - - case OpenApiSpecVersion.OpenApi3_0: - default: - swagger.SerializeAsV3(writer); - break; - } + swagger.SerializeAs(specVersion, writer); } if (outputPath != null) diff --git a/src/Swashbuckle.AspNetCore.Newtonsoft/Swashbuckle.AspNetCore.Newtonsoft.csproj b/src/Swashbuckle.AspNetCore.Newtonsoft/Swashbuckle.AspNetCore.Newtonsoft.csproj index b44f8652fb..f2b1cc15ea 100644 --- a/src/Swashbuckle.AspNetCore.Newtonsoft/Swashbuckle.AspNetCore.Newtonsoft.csproj +++ b/src/Swashbuckle.AspNetCore.Newtonsoft/Swashbuckle.AspNetCore.Newtonsoft.csproj @@ -22,6 +22,10 @@ + + + + diff --git a/src/Swashbuckle.AspNetCore.ReDoc/Swashbuckle.AspNetCore.ReDoc.csproj b/src/Swashbuckle.AspNetCore.ReDoc/Swashbuckle.AspNetCore.ReDoc.csproj index 52c1c86fe5..ae62253e06 100644 --- a/src/Swashbuckle.AspNetCore.ReDoc/Swashbuckle.AspNetCore.ReDoc.csproj +++ b/src/Swashbuckle.AspNetCore.ReDoc/Swashbuckle.AspNetCore.ReDoc.csproj @@ -78,7 +78,7 @@ - <_SdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net9.0 + <_SdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net10.0 <_SdkTasksTFM Condition=" '$(MSBuildRuntimeType)' != 'Core'">net472 diff --git a/src/Swashbuckle.AspNetCore.Swagger/IAsyncSwaggerProvider.cs b/src/Swashbuckle.AspNetCore.Swagger/IAsyncSwaggerProvider.cs index 8224c06638..6ca2f6bd0e 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/IAsyncSwaggerProvider.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/IAsyncSwaggerProvider.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.Swagger; diff --git a/src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs b/src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs index e69c1e3ffc..9ee2edf303 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/ISwaggerDocumentSerializer.cs @@ -1,6 +1,4 @@ using Microsoft.OpenApi; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Writers; namespace Swashbuckle.AspNetCore.Swagger; diff --git a/src/Swashbuckle.AspNetCore.Swagger/ISwaggerProvider.cs b/src/Swashbuckle.AspNetCore.Swagger/ISwaggerProvider.cs index 066884fac4..3b6ce2f0c1 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/ISwaggerProvider.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/ISwaggerProvider.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.Swagger; diff --git a/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Shipped.txt b/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Shipped.txt index 2ea801b6d3..a0d2fb49b5 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Shipped.txt @@ -7,24 +7,19 @@ static Microsoft.AspNetCore.Builder.SwaggerBuilderExtensions.UseSwagger(this Mic static Microsoft.Extensions.DependencyInjection.SwaggerOptionsExtensions.SetCustomDocumentSerializer(this Swashbuckle.AspNetCore.Swagger.SwaggerOptions swaggerOptions, params object[] constructorParameters) -> void static Microsoft.Extensions.DependencyInjection.SwaggerServiceCollectionExtensions.ConfigureSwagger(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action setupAction) -> void Swashbuckle.AspNetCore.Swagger.IAsyncSwaggerProvider -Swashbuckle.AspNetCore.Swagger.IAsyncSwaggerProvider.GetSwaggerAsync(string documentName, string host = null, string basePath = null) -> System.Threading.Tasks.Task Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentMetadataProvider Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentMetadataProvider.GetDocumentNames() -> System.Collections.Generic.IList Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentSerializer -Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentSerializer.SerializeDocument(Microsoft.OpenApi.Models.OpenApiDocument document, Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) -> void Swashbuckle.AspNetCore.Swagger.ISwaggerProvider -Swashbuckle.AspNetCore.Swagger.ISwaggerProvider.GetSwagger(string documentName, string host = null, string basePath = null) -> Microsoft.OpenApi.Models.OpenApiDocument Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.OpenApiVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.OpenApiVersion.set -> void -Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.PreSerializeFilters.get -> System.Collections.Generic.List> Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.SwaggerEndpointOptions() -> void Swashbuckle.AspNetCore.Swagger.SwaggerOptions Swashbuckle.AspNetCore.Swagger.SwaggerOptions.CustomDocumentSerializer.get -> Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentSerializer Swashbuckle.AspNetCore.Swagger.SwaggerOptions.CustomDocumentSerializer.set -> void Swashbuckle.AspNetCore.Swagger.SwaggerOptions.OpenApiVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion Swashbuckle.AspNetCore.Swagger.SwaggerOptions.OpenApiVersion.set -> void -Swashbuckle.AspNetCore.Swagger.SwaggerOptions.PreSerializeFilters.get -> System.Collections.Generic.List> Swashbuckle.AspNetCore.Swagger.SwaggerOptions.RouteTemplate.get -> string Swashbuckle.AspNetCore.Swagger.SwaggerOptions.RouteTemplate.set -> void Swashbuckle.AspNetCore.Swagger.SwaggerOptions.SwaggerOptions() -> void diff --git a/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Unshipped.txt b/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Unshipped.txt index 5f282702bb..f5d8dc9185 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Swashbuckle.AspNetCore.Swagger/PublicAPI/PublicAPI.Unshipped.txt @@ -1 +1,5 @@ - \ No newline at end of file +Swashbuckle.AspNetCore.Swagger.IAsyncSwaggerProvider.GetSwaggerAsync(string documentName, string host = null, string basePath = null) -> System.Threading.Tasks.Task +Swashbuckle.AspNetCore.Swagger.ISwaggerDocumentSerializer.SerializeDocument(Microsoft.OpenApi.OpenApiDocument document, Microsoft.OpenApi.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) -> void +Swashbuckle.AspNetCore.Swagger.ISwaggerProvider.GetSwagger(string documentName, string host = null, string basePath = null) -> Microsoft.OpenApi.OpenApiDocument +Swashbuckle.AspNetCore.Swagger.SwaggerEndpointOptions.PreSerializeFilters.get -> System.Collections.Generic.List> +Swashbuckle.AspNetCore.Swagger.SwaggerOptions.PreSerializeFilters.get -> System.Collections.Generic.List> diff --git a/src/Swashbuckle.AspNetCore.Swagger/SwaggerEndpointOptions.cs b/src/Swashbuckle.AspNetCore.Swagger/SwaggerEndpointOptions.cs index a45d792d3c..9a8ebcb256 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/SwaggerEndpointOptions.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/SwaggerEndpointOptions.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.OpenApi; -using Microsoft.OpenApi.Models; namespace Swashbuckle.AspNetCore.Swagger; diff --git a/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs b/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs index 944dcac9f8..1256335bd8 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/SwaggerMiddleware.cs @@ -5,8 +5,7 @@ using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Template; using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.Swagger; @@ -174,17 +173,7 @@ private void SerializeDocument( } else { - switch (_options.OpenApiVersion) - { - case Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0: - document.SerializeAsV2(writer); - break; - - case Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0: - default: - document.SerializeAsV3(writer); - break; - } + document.SerializeAs(_options.OpenApiVersion, writer); } } } diff --git a/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs b/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs index 4ee7f48ed2..afea3d4df2 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs +++ b/src/Swashbuckle.AspNetCore.Swagger/SwaggerOptions.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.OpenApi; -using Microsoft.OpenApi.Models; namespace Swashbuckle.AspNetCore.Swagger; diff --git a/src/Swashbuckle.AspNetCore.Swagger/Swashbuckle.AspNetCore.Swagger.csproj b/src/Swashbuckle.AspNetCore.Swagger/Swashbuckle.AspNetCore.Swagger.csproj index 6346a9732e..40de95884b 100644 --- a/src/Swashbuckle.AspNetCore.Swagger/Swashbuckle.AspNetCore.Swagger.csproj +++ b/src/Swashbuckle.AspNetCore.Swagger/Swashbuckle.AspNetCore.Swagger.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs index 6017437bf7..09b2dc9397 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSchemaGeneratorOptions.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -22,7 +22,7 @@ public void Configure(SchemaGeneratorOptions options) private static void DeepCopy(SchemaGeneratorOptions source, SchemaGeneratorOptions target) { - target.CustomTypeMappings = new Dictionary>(source.CustomTypeMappings); + target.CustomTypeMappings = new Dictionary>(source.CustomTypeMappings); target.UseInlineDefinitionsForEnums = source.UseInlineDefinitionsForEnums; target.SchemaIdSelector = source.SchemaIdSelector; target.IgnoreObsoleteProperties = source.IgnoreObsoleteProperties; diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs index bf9bea3344..846ab0c327 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/ConfigureSwaggerGeneratorOptions.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -91,7 +91,7 @@ public static void DeepCopy(SwaggerGeneratorOptions source, SwaggerGeneratorOpti target.DescribeAllParametersInCamelCase = source.DescribeAllParametersInCamelCase; target.SchemaComparer = source.SchemaComparer; target.Servers = [.. source.Servers]; - target.SecuritySchemes = new Dictionary(source.SecuritySchemes); + target.SecuritySchemes = new Dictionary(source.SecuritySchemes); target.SecurityRequirements = [.. source.SecurityRequirements]; target.ParameterFilters = [.. source.ParameterFilters]; target.ParameterAsyncFilters = [.. source.ParameterAsyncFilters]; diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs index d46da87d53..649d0bef3e 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/DocumentProvider.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; @@ -29,17 +29,7 @@ public async Task GenerateAsync(string documentName, TextWriter writer) } else { - switch (_options.OpenApiVersion) - { - case OpenApi.OpenApiSpecVersion.OpenApi2_0: - swagger.SerializeAsV2(jsonWriter); - break; - - default: - case OpenApi.OpenApiSpecVersion.OpenApi3_0: - swagger.SerializeAsV3(jsonWriter); - break; - } + swagger.SerializeAs(_options.OpenApiVersion, jsonWriter); } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs index c2df6a5b4a..dc4f4df057 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/DependencyInjection/SwaggerGenOptionsExtensions.cs @@ -2,7 +2,7 @@ using System.Xml.XPath; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Microsoft.Extensions.DependencyInjection; @@ -132,7 +132,7 @@ public static void AddServer(this SwaggerGenOptions swaggerGenOptions, OpenApiSe public static void AddSecurityDefinition( this SwaggerGenOptions swaggerGenOptions, string name, - OpenApiSecurityScheme securityScheme) + IOpenApiSecurityScheme securityScheme) { swaggerGenOptions.SwaggerGeneratorOptions.SecuritySchemes.Add(name, securityScheme); } @@ -147,7 +147,7 @@ public static void AddSecurityDefinition( /// public static void AddSecurityRequirement( this SwaggerGenOptions swaggerGenOptions, - OpenApiSecurityRequirement securityRequirement) + Func securityRequirement) { swaggerGenOptions.SwaggerGeneratorOptions.SecurityRequirements.Add(securityRequirement); } @@ -161,7 +161,7 @@ public static void AddSecurityRequirement( public static void MapType( this SwaggerGenOptions swaggerGenOptions, Type type, - Func schemaFactory) + Func schemaFactory) { swaggerGenOptions.SchemaGeneratorOptions.CustomTypeMappings.Add(type, schemaFactory); } @@ -174,7 +174,7 @@ public static void MapType( /// A factory method that generates Schema's for the provided type public static void MapType( this SwaggerGenOptions swaggerGenOptions, - Func schemaFactory) + Func schemaFactory) { swaggerGenOptions.MapType(typeof(T), schemaFactory); } @@ -312,7 +312,7 @@ public static void NonNullableReferenceTypesAsRequired(this SwaggerGenOptions sw /// Currently only supports JWT Bearer authentication public static void InferSecuritySchemes( this SwaggerGenOptions swaggerGenOptions, - Func, IDictionary> securitySchemesSelector = null) + Func, IDictionary> securitySchemesSelector = null) { swaggerGenOptions.SwaggerGeneratorOptions.InferSecuritySchemes = true; swaggerGenOptions.SwaggerGeneratorOptions.SecuritySchemesSelector = securitySchemesSelector; diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/JsonModelFactory.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/JsonModelFactory.cs index c7b230400a..afebf6e5ac 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/JsonModelFactory.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/JsonModelFactory.cs @@ -1,10 +1,9 @@ -using Microsoft.OpenApi.Any; -using Swashbuckle.AspNetCore.SwaggerGen; +using System.Text.Json.Nodes; namespace Swashbuckle.AspNetCore; internal static class JsonModelFactory { - public static IOpenApiAny CreateFromJson(string json) - => OpenApiAnyFactory.CreateFromJson(json); + public static JsonNode CreateFromJson(string json) + => json is null ? null : JsonNode.Parse(json); } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Shipped.txt b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Shipped.txt index da26904fbb..5d4ff3cf46 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Shipped.txt +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Shipped.txt @@ -9,9 +9,6 @@ static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddP static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddRequestBodyAsyncFilterInstance(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, TFilter filterInstance) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddRequestBodyFilterInstance(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, TFilter filterInstance) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddSchemaFilterInstance(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, TFilter filterInstance) -> void -static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddSecurityDefinition(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, string name, Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) -> void -static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddSecurityRequirement(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) -> void -static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddServer(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, Microsoft.OpenApi.Models.OpenApiServer server) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.CustomOperationIds(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func operationIdSelector) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.CustomSchemaIds(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func schemaIdSelector) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.DescribeAllParametersInCamelCase(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions) -> void @@ -23,9 +20,6 @@ static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.Igno static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.IncludeXmlComments(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, string filePath, bool includeControllerXmlComments = false) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.IncludeXmlComments(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func xmlDocFactory, bool includeControllerXmlComments = false) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.IncludeXmlComments(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Reflection.Assembly assembly, bool includeControllerXmlComments = false) -> void -static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.InferSecuritySchemes(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func, System.Collections.Generic.IDictionary> securitySchemesSelector = null) -> void -static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.MapType(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Type type, System.Func schemaFactory) -> void -static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.MapType(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func schemaFactory) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.NonNullableReferenceTypesAsRequired(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.OperationAsyncFilter(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, params object[] arguments) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.OperationFilter(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, params object[] arguments) -> void @@ -41,7 +35,6 @@ static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.Sele static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.SelectSubTypesUsing(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func> customSelector) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.SortSchemasWith(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Collections.Generic.IComparer schemaComparer) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.SupportNonNullableReferenceTypes(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions) -> void -static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.SwaggerDoc(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, string name, Microsoft.OpenApi.Models.OpenApiInfo info) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.TagActionsBy(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func> tagsSelector) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.UseAllOfForInheritance(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions) -> void static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.UseAllOfToExtendReferenceSchemas(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions) -> void @@ -64,8 +57,6 @@ static Swashbuckle.AspNetCore.SwaggerGen.MemberInfoExtensions.GetInlineAndMetada static Swashbuckle.AspNetCore.SwaggerGen.MemberInfoExtensions.IsDictionaryValueNonNullable(this System.Reflection.MemberInfo memberInfo) -> bool static Swashbuckle.AspNetCore.SwaggerGen.MemberInfoExtensions.IsNonNullableReferenceType(this System.Reflection.MemberInfo memberInfo) -> bool static Swashbuckle.AspNetCore.SwaggerGen.MethodInfoExtensions.GetUnderlyingGenericTypeMethod(this System.Reflection.MethodInfo constructedTypeMethod) -> System.Reflection.MethodInfo -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiSchemaExtensions.ApplyRouteConstraints(this Microsoft.OpenApi.Models.OpenApiSchema schema, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo routeInfo) -> void -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiSchemaExtensions.ApplyValidationAttributes(this Microsoft.OpenApi.Models.OpenApiSchema schema, System.Collections.Generic.IEnumerable customAttributes) -> void static Swashbuckle.AspNetCore.SwaggerGen.PropertyInfoExtensions.HasAttribute(this System.Reflection.PropertyInfo property) -> bool static Swashbuckle.AspNetCore.SwaggerGen.PropertyInfoExtensions.IsPubliclyReadable(this System.Reflection.PropertyInfo property) -> bool static Swashbuckle.AspNetCore.SwaggerGen.PropertyInfoExtensions.IsPubliclyWritable(this System.Reflection.PropertyInfo property) -> bool @@ -132,25 +123,15 @@ Swashbuckle.AspNetCore.SwaggerGen.FilterDescriptor.Type.get -> System.Type Swashbuckle.AspNetCore.SwaggerGen.FilterDescriptor.Type.set -> void Swashbuckle.AspNetCore.SwaggerGen.IDictionary Swashbuckle.AspNetCore.SwaggerGen.IDocumentAsyncFilter -Swashbuckle.AspNetCore.SwaggerGen.IDocumentAsyncFilter.ApplyAsync(Microsoft.OpenApi.Models.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task Swashbuckle.AspNetCore.SwaggerGen.IDocumentFilter -Swashbuckle.AspNetCore.SwaggerGen.IDocumentFilter.Apply(Microsoft.OpenApi.Models.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context) -> void Swashbuckle.AspNetCore.SwaggerGen.IOperationAsyncFilter -Swashbuckle.AspNetCore.SwaggerGen.IOperationAsyncFilter.ApplyAsync(Microsoft.OpenApi.Models.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task Swashbuckle.AspNetCore.SwaggerGen.IOperationFilter -Swashbuckle.AspNetCore.SwaggerGen.IOperationFilter.Apply(Microsoft.OpenApi.Models.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context) -> void Swashbuckle.AspNetCore.SwaggerGen.IParameterAsyncFilter -Swashbuckle.AspNetCore.SwaggerGen.IParameterAsyncFilter.ApplyAsync(Microsoft.OpenApi.Models.OpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task Swashbuckle.AspNetCore.SwaggerGen.IParameterFilter -Swashbuckle.AspNetCore.SwaggerGen.IParameterFilter.Apply(Microsoft.OpenApi.Models.OpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context) -> void Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyAsyncFilter -Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyAsyncFilter.ApplyAsync(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyFilter -Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyFilter.Apply(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context) -> void Swashbuckle.AspNetCore.SwaggerGen.ISchemaFilter -Swashbuckle.AspNetCore.SwaggerGen.ISchemaFilter.Apply(Microsoft.OpenApi.Models.OpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext context) -> void Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator -Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator.GenerateSchema(System.Type modelType, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, System.Reflection.MemberInfo memberInfo = null, System.Reflection.ParameterInfo parameterInfo = null, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo routeInfo = null) -> Microsoft.OpenApi.Models.OpenApiSchema Swashbuckle.AspNetCore.SwaggerGen.ISerializerDataContractResolver Swashbuckle.AspNetCore.SwaggerGen.ISerializerDataContractResolver.GetDataContractForType(System.Type type) -> Swashbuckle.AspNetCore.SwaggerGen.DataContract Swashbuckle.AspNetCore.SwaggerGen.JsonSerializerDataContractResolver @@ -165,13 +146,11 @@ Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.ApiDescription.get -> Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.DocumentName.get -> string Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.MethodInfo.get -> System.Reflection.MethodInfo -Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.OperationFilterContext(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription apiDescription, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaRegistry, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, System.Reflection.MethodInfo methodInfo) -> void Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.SchemaGenerator.get -> Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.SchemaRepository.get -> Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.ApiParameterDescription.get -> Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.DocumentName.get -> string -Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.ParameterFilterContext(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription apiParameterDescription, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaGenerator, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, System.Reflection.PropertyInfo propertyInfo = null, System.Reflection.ParameterInfo parameterInfo = null) -> void Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.ParameterInfo.get -> System.Reflection.ParameterInfo Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.PropertyInfo.get -> System.Reflection.PropertyInfo Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.SchemaGenerator.get -> Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator @@ -181,7 +160,6 @@ Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.BodyParameterDescription.get -> Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.DocumentName.get -> string Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.FormParameterDescriptions.get -> System.Collections.Generic.IEnumerable -Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.RequestBodyFilterContext(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription bodyParameterDescription, System.Collections.Generic.IEnumerable formParameterDescriptions, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaGenerator, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository) -> void Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.SchemaGenerator.get -> Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.SchemaRepository.get -> Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext @@ -193,10 +171,8 @@ Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext.SchemaGenerator.get -> Swa Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext.SchemaRepository.get -> Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext.Type.get -> System.Type Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator -Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateSchema(System.Type modelType, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, System.Reflection.MemberInfo memberInfo = null, System.Reflection.ParameterInfo parameterInfo = null, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo routeInfo = null) -> Microsoft.OpenApi.Models.OpenApiSchema Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.SchemaGenerator(Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions generatorOptions, Swashbuckle.AspNetCore.SwaggerGen.ISerializerDataContractResolver serializerDataContractResolver) -> void Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions -Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.CustomTypeMappings.get -> System.Collections.Generic.IDictionary> Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.CustomTypeMappings.set -> void Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.DiscriminatorNameSelector.get -> System.Func Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.DiscriminatorNameSelector.set -> void @@ -224,19 +200,14 @@ Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.UseInlineDefinitionsFor Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.UseOneOfForPolymorphism.get -> bool Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.UseOneOfForPolymorphism.set -> void Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository -Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.AddDefinition(string schemaId, Microsoft.OpenApi.Models.OpenApiSchema schema) -> Microsoft.OpenApi.Models.OpenApiSchema Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.DocumentName.get -> string Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.RegisterType(System.Type type, string schemaId) -> void Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.SchemaRepository(string documentName = null) -> void -Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.Schemas.get -> System.Collections.Generic.Dictionary -Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.TryLookupByType(System.Type type, out Microsoft.OpenApi.Models.OpenApiSchema referenceSchema) -> bool Swashbuckle.AspNetCore.SwaggerGen.SwaggerApplicationConvention Swashbuckle.AspNetCore.SwaggerGen.SwaggerApplicationConvention.Apply(Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel application) -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerApplicationConvention.SwaggerApplicationConvention() -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetDocumentNames() -> System.Collections.Generic.IList -Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(string documentName, string host = null, string basePath = null) -> Microsoft.OpenApi.Models.OpenApiDocument -Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwaggerAsync(string documentName, string host = null, string basePath = null) -> System.Threading.Tasks.Task Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.SwaggerGenerator(Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options, Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionGroupCollectionProvider apiDescriptionsProvider, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaGenerator) -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.SwaggerGenerator(Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options, Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionGroupCollectionProvider apiDescriptionsProvider, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaGenerator, Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider authenticationSchemeProvider) -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException @@ -275,17 +246,12 @@ Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.RequestBodyFilters.get Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.RequestBodyFilters.set -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SchemaComparer.get -> System.Collections.Generic.IComparer Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SchemaComparer.set -> void -Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecurityRequirements.get -> System.Collections.Generic.IList Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecurityRequirements.set -> void -Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecuritySchemes.get -> System.Collections.Generic.IDictionary Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecuritySchemes.set -> void -Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecuritySchemesSelector.get -> System.Func, System.Collections.Generic.IDictionary> Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecuritySchemesSelector.set -> void -Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.Servers.get -> System.Collections.Generic.List Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.Servers.set -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SortKeySelector.get -> System.Func Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SortKeySelector.set -> void -Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SwaggerDocs.get -> System.Collections.Generic.IDictionary Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SwaggerDocs.set -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SwaggerGeneratorOptions() -> void Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.TagsSelector.get -> System.Func> @@ -310,21 +276,10 @@ Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions.SwaggerGeneratorOptions.set Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions.SwaggerGenOptions() -> void Swashbuckle.AspNetCore.SwaggerGen.TypeExtensions Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsDocumentFilter -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsDocumentFilter.Apply(Microsoft.OpenApi.Models.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context) -> void -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsDocumentFilter.XmlCommentsDocumentFilter(System.Xml.XPath.XPathDocument xmlDoc) -> void -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsDocumentFilter.XmlCommentsDocumentFilter(System.Xml.XPath.XPathDocument xmlDoc, Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options) -> void Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsNodeNameHelper Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsNodeNameHelper.XmlCommentsNodeNameHelper() -> void Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsOperationFilter -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsOperationFilter.Apply(Microsoft.OpenApi.Models.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context) -> void -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsOperationFilter.XmlCommentsOperationFilter(System.Xml.XPath.XPathDocument xmlDoc) -> void Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter.Apply(Microsoft.OpenApi.Models.OpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context) -> void -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter.XmlCommentsParameterFilter(System.Xml.XPath.XPathDocument xmlDoc) -> void Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsRequestBodyFilter -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsRequestBodyFilter.Apply(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context) -> void -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsRequestBodyFilter.XmlCommentsRequestBodyFilter(System.Xml.XPath.XPathDocument xmlDoc) -> void Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsSchemaFilter -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsSchemaFilter.Apply(Microsoft.OpenApi.Models.OpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext context) -> void -Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsSchemaFilter.XmlCommentsSchemaFilter(System.Xml.XPath.XPathDocument xmlDoc) -> void Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsTextHelper diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Unshipped.txt b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Unshipped.txt index e69de29bb2..7e384c4c92 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/PublicAPI.Unshipped.txt @@ -0,0 +1,47 @@ +static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddSecurityDefinition(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, string name, Microsoft.OpenApi.IOpenApiSecurityScheme securityScheme) -> void +static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddSecurityRequirement(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func securityRequirement) -> void +static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.AddServer(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, Microsoft.OpenApi.OpenApiServer server) -> void +static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.InferSecuritySchemes(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func, System.Collections.Generic.IDictionary> securitySchemesSelector = null) -> void +static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.MapType(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Type type, System.Func schemaFactory) -> void +static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.MapType(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, System.Func schemaFactory) -> void +static Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.SwaggerDoc(this Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenOptions swaggerGenOptions, string name, Microsoft.OpenApi.OpenApiInfo info) -> void +static Swashbuckle.AspNetCore.SwaggerGen.OpenApiSchemaExtensions.ApplyRouteConstraints(this Microsoft.OpenApi.IOpenApiSchema schema, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo routeInfo) -> void +static Swashbuckle.AspNetCore.SwaggerGen.OpenApiSchemaExtensions.ApplyValidationAttributes(this Microsoft.OpenApi.IOpenApiSchema schema, System.Collections.Generic.IEnumerable customAttributes) -> void +Swashbuckle.AspNetCore.SwaggerGen.IDocumentAsyncFilter.ApplyAsync(Microsoft.OpenApi.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +Swashbuckle.AspNetCore.SwaggerGen.IDocumentFilter.Apply(Microsoft.OpenApi.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.IOperationAsyncFilter.ApplyAsync(Microsoft.OpenApi.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +Swashbuckle.AspNetCore.SwaggerGen.IOperationFilter.Apply(Microsoft.OpenApi.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.IParameterAsyncFilter.ApplyAsync(Microsoft.OpenApi.IOpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +Swashbuckle.AspNetCore.SwaggerGen.IParameterFilter.Apply(Microsoft.OpenApi.IOpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyAsyncFilter.ApplyAsync(Microsoft.OpenApi.IOpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task +Swashbuckle.AspNetCore.SwaggerGen.IRequestBodyFilter.Apply(Microsoft.OpenApi.IOpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.ISchemaFilter.Apply(Microsoft.OpenApi.IOpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator.GenerateSchema(System.Type modelType, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, System.Reflection.MemberInfo memberInfo = null, System.Reflection.ParameterInfo parameterInfo = null, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo routeInfo = null) -> Microsoft.OpenApi.IOpenApiSchema +Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.Document.get -> Microsoft.OpenApi.OpenApiDocument +Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext.OperationFilterContext(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription apiDescription, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaRegistry, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, Microsoft.OpenApi.OpenApiDocument document, System.Reflection.MethodInfo methodInfo) -> void +Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.Document.get -> Microsoft.OpenApi.OpenApiDocument +Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext.ParameterFilterContext(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription apiParameterDescription, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaGenerator, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, Microsoft.OpenApi.OpenApiDocument document, System.Reflection.PropertyInfo propertyInfo = null, System.Reflection.ParameterInfo parameterInfo = null) -> void +Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.Document.get -> Microsoft.OpenApi.OpenApiDocument +Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext.RequestBodyFilterContext(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription bodyParameterDescription, System.Collections.Generic.IEnumerable formParameterDescriptions, Swashbuckle.AspNetCore.SwaggerGen.ISchemaGenerator schemaGenerator, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, Microsoft.OpenApi.OpenApiDocument document) -> void +Swashbuckle.AspNetCore.SwaggerGen.SchemaGenerator.GenerateSchema(System.Type modelType, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository, System.Reflection.MemberInfo memberInfo = null, System.Reflection.ParameterInfo parameterInfo = null, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo routeInfo = null) -> Microsoft.OpenApi.IOpenApiSchema +Swashbuckle.AspNetCore.SwaggerGen.SchemaGeneratorOptions.CustomTypeMappings.get -> System.Collections.Generic.IDictionary> +Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.AddDefinition(string schemaId, Microsoft.OpenApi.OpenApiSchema schema) -> Microsoft.OpenApi.OpenApiSchemaReference +Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.Schemas.get -> System.Collections.Generic.Dictionary +Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository.TryLookupByType(System.Type type, out Microsoft.OpenApi.OpenApiSchemaReference referenceSchema) -> bool +Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(string documentName, string host = null, string basePath = null) -> Microsoft.OpenApi.OpenApiDocument +Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwaggerAsync(string documentName, string host = null, string basePath = null) -> System.Threading.Tasks.Task +Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecurityRequirements.get -> System.Collections.Generic.IList> +Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecuritySchemes.get -> System.Collections.Generic.IDictionary +Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SecuritySchemesSelector.get -> System.Func, System.Collections.Generic.IDictionary> +Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.Servers.get -> System.Collections.Generic.List +Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions.SwaggerDocs.get -> System.Collections.Generic.IDictionary +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsDocumentFilter.Apply(Microsoft.OpenApi.OpenApiDocument swaggerDoc, Swashbuckle.AspNetCore.SwaggerGen.DocumentFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsDocumentFilter.XmlCommentsDocumentFilter(System.Collections.Generic.IReadOnlyDictionary xmlDocMembers, Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsOperationFilter.Apply(Microsoft.OpenApi.OpenApiOperation operation, Swashbuckle.AspNetCore.SwaggerGen.OperationFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsOperationFilter.XmlCommentsOperationFilter(System.Collections.Generic.IReadOnlyDictionary xmlDocMembers, Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter.Apply(Microsoft.OpenApi.IOpenApiParameter parameter, Swashbuckle.AspNetCore.SwaggerGen.ParameterFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsParameterFilter.XmlCommentsParameterFilter(System.Collections.Generic.IReadOnlyDictionary xmlDocMembers, Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsRequestBodyFilter.Apply(Microsoft.OpenApi.IOpenApiRequestBody requestBody, Swashbuckle.AspNetCore.SwaggerGen.RequestBodyFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsRequestBodyFilter.XmlCommentsRequestBodyFilter(System.Collections.Generic.IReadOnlyDictionary xmlDocMembers, Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsSchemaFilter.Apply(Microsoft.OpenApi.IOpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaFilterContext context) -> void +Swashbuckle.AspNetCore.SwaggerGen.XmlCommentsSchemaFilter.XmlCommentsSchemaFilter(System.Collections.Generic.IReadOnlyDictionary xmlDocMembers, Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorOptions options) -> void diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net8.0/PublicAPI.Shipped.txt b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net8.0/PublicAPI.Shipped.txt deleted file mode 100644 index 02932c3763..0000000000 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net8.0/PublicAPI.Shipped.txt +++ /dev/null @@ -1,4 +0,0 @@ -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiAnyFactory.CreateFromJson(string json) -> Microsoft.OpenApi.Any.IOpenApiAny -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiAnyFactory.CreateFromJson(string json, System.Text.Json.JsonSerializerOptions options) -> Microsoft.OpenApi.Any.IOpenApiAny -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiSchemaExtensions.ResolveType(this Microsoft.OpenApi.Models.OpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository) -> string -Swashbuckle.AspNetCore.SwaggerGen.OpenApiAnyFactory diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net8.0/PublicAPI.Unshipped.txt deleted file mode 100644 index 5f282702bb..0000000000 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net9.0/PublicAPI.Shipped.txt b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net9.0/PublicAPI.Shipped.txt deleted file mode 100644 index 02932c3763..0000000000 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net9.0/PublicAPI.Shipped.txt +++ /dev/null @@ -1,4 +0,0 @@ -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiAnyFactory.CreateFromJson(string json) -> Microsoft.OpenApi.Any.IOpenApiAny -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiAnyFactory.CreateFromJson(string json, System.Text.Json.JsonSerializerOptions options) -> Microsoft.OpenApi.Any.IOpenApiAny -static Swashbuckle.AspNetCore.SwaggerGen.OpenApiSchemaExtensions.ResolveType(this Microsoft.OpenApi.Models.OpenApiSchema schema, Swashbuckle.AspNetCore.SwaggerGen.SchemaRepository schemaRepository) -> string -Swashbuckle.AspNetCore.SwaggerGen.OpenApiAnyFactory diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net9.0/PublicAPI.Unshipped.txt b/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net9.0/PublicAPI.Unshipped.txt deleted file mode 100644 index 5f282702bb..0000000000 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/PublicAPI/net9.0/PublicAPI.Unshipped.txt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/ISchemaFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/ISchemaFilter.cs index 6dbebbae80..49d80112fb 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/ISchemaFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/ISchemaFilter.cs @@ -1,8 +1,8 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; public interface ISchemaFilter { - void Apply(OpenApiSchema schema, SchemaFilterContext context); + void Apply(IOpenApiSchema schema, SchemaFilterContext context); } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/OpenApiSchemaExtensions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/OpenApiSchemaExtensions.cs index 68071983f4..34d0c3eae9 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/OpenApiSchemaExtensions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/OpenApiSchemaExtensions.cs @@ -3,7 +3,7 @@ using System.Globalization; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Routing.Constraints; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using AnnotationsDataType = System.ComponentModel.DataAnnotations.DataType; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -30,7 +30,15 @@ public static class OpenApiSchemaExtensions [AnnotationsDataType.Upload] = "binary", }; - public static void ApplyValidationAttributes(this OpenApiSchema schema, IEnumerable customAttributes) + public static void ApplyValidationAttributes(this IOpenApiSchema schema, IEnumerable customAttributes) + { + if (schema is OpenApiSchema concrete) + { + ApplyValidationAttributes(concrete, customAttributes); + } + } + + private static void ApplyValidationAttributes(OpenApiSchema schema, IEnumerable customAttributes) { foreach (var attribute in customAttributes) { @@ -77,7 +85,15 @@ public static void ApplyValidationAttributes(this OpenApiSchema schema, IEnumera } } - public static void ApplyRouteConstraints(this OpenApiSchema schema, ApiParameterRouteInfo routeInfo) + public static void ApplyRouteConstraints(this IOpenApiSchema schema, ApiParameterRouteInfo routeInfo) + { + if (schema is OpenApiSchema concrete) + { + ApplyRouteConstraints(concrete, routeInfo); + } + } + + private static void ApplyRouteConstraints(OpenApiSchema schema, ApiParameterRouteInfo routeInfo) { foreach (var constraint in routeInfo.Constraints) { @@ -128,19 +144,23 @@ public static void ApplyRouteConstraints(this OpenApiSchema schema, ApiParameter } } - public static string ResolveType(this OpenApiSchema schema, SchemaRepository schemaRepository) + internal static JsonSchemaType? ResolveType(this IOpenApiSchema schema, SchemaRepository schemaRepository) { - if (schema.Reference != null && schemaRepository.Schemas.TryGetValue(schema.Reference.Id, out OpenApiSchema definitionSchema)) + if (schema is OpenApiSchemaReference reference && + schemaRepository.Schemas.TryGetValue(reference.Reference.Id, out var definitionSchema)) { return definitionSchema.ResolveType(schemaRepository); } - foreach (var subSchema in schema.AllOf) + if (schema.AllOf is { Count: > 0 } allOf) { - var type = subSchema.ResolveType(schemaRepository); - if (type != null) + foreach (var subSchema in allOf) { - return type; + var type = subSchema.ResolveType(schemaRepository); + if (type != null) + { + return type; + } } } @@ -157,7 +177,7 @@ private static void ApplyDataTypeAttribute(OpenApiSchema schema, DataTypeAttribu private static void ApplyMinLengthAttribute(OpenApiSchema schema, MinLengthAttribute minLengthAttribute) { - if (schema.Type == JsonSchemaTypes.Array) + if (schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Array)) { schema.MinItems = minLengthAttribute.Length; } @@ -169,7 +189,7 @@ private static void ApplyMinLengthAttribute(OpenApiSchema schema, MinLengthAttri private static void ApplyMinLengthRouteConstraint(OpenApiSchema schema, MinLengthRouteConstraint minLengthRouteConstraint) { - if (schema.Type == JsonSchemaTypes.Array) + if (schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Array)) { schema.MinItems = minLengthRouteConstraint.MinLength; } @@ -181,7 +201,7 @@ private static void ApplyMinLengthRouteConstraint(OpenApiSchema schema, MinLengt private static void ApplyMaxLengthAttribute(OpenApiSchema schema, MaxLengthAttribute maxLengthAttribute) { - if (schema.Type == JsonSchemaTypes.Array) + if (schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Array)) { schema.MaxItems = maxLengthAttribute.Length; } @@ -193,7 +213,7 @@ private static void ApplyMaxLengthAttribute(OpenApiSchema schema, MaxLengthAttri private static void ApplyMaxLengthRouteConstraint(OpenApiSchema schema, MaxLengthRouteConstraint maxLengthRouteConstraint) { - if (schema.Type == JsonSchemaTypes.Array) + if (schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Array)) { schema.MaxItems = maxLengthRouteConstraint.MaxLength; } @@ -205,7 +225,7 @@ private static void ApplyMaxLengthRouteConstraint(OpenApiSchema schema, MaxLengt private static void ApplyLengthAttribute(OpenApiSchema schema, LengthAttribute lengthAttribute) { - if (schema.Type == JsonSchemaTypes.Array) + if (schema.Type is { } type && type.HasFlag(JsonSchemaTypes.Array)) { schema.MinItems = lengthAttribute.MinimumLength; schema.MaxItems = lengthAttribute.MaximumLength; @@ -224,11 +244,16 @@ private static void ApplyBase64Attribute(OpenApiSchema schema) private static void ApplyRangeAttribute(OpenApiSchema schema, RangeAttribute rangeAttribute) { - if (rangeAttribute.Maximum is int maximumInteger) + object maximumValue = null; + object minimumValue = null; + + if (rangeAttribute.Maximum is double || rangeAttribute.Minimum is int) { - // The range was set with the RangeAttribute(int, int) constructor - schema.Maximum = maximumInteger; - schema.Minimum = (int)rangeAttribute.Minimum; + // The range was set with the RangeAttribute(double, double) or RangeAttribute(int, int) + // constructor so we can safely convert the values to strings using the invariant culture + // as we have primitive values to operate on. + maximumValue = rangeAttribute.Maximum; + minimumValue = rangeAttribute.Minimum; } else { @@ -245,37 +270,48 @@ private static void ApplyRangeAttribute(OpenApiSchema schema, RangeAttribute ran if (decimal.TryParse(maxString, NumberStyles.Any, targetCulture, out var value)) { - schema.Maximum = value; + maximumValue = value; } if (decimal.TryParse(minString, NumberStyles.Any, targetCulture, out value)) { - schema.Minimum = value; + minimumValue = value; } } - if (rangeAttribute.MinimumIsExclusive) + // Ensure that the conversion to string is done using the invariant culture so valid JSON is generated + if (maximumValue is not null) + { + schema.Maximum = Convert.ToString(maximumValue, CultureInfo.InvariantCulture); + } + + if (minimumValue is not null) { - schema.ExclusiveMinimum = true; + schema.Minimum = Convert.ToString(minimumValue, CultureInfo.InvariantCulture); } if (rangeAttribute.MaximumIsExclusive) { - schema.ExclusiveMaximum = true; + schema.ExclusiveMaximum = schema.Maximum; + } + + if (rangeAttribute.MinimumIsExclusive) + { + schema.ExclusiveMinimum = schema.Minimum; } } private static void ApplyRangeRouteConstraint(OpenApiSchema schema, RangeRouteConstraint rangeRouteConstraint) { - schema.Maximum = rangeRouteConstraint.Max; - schema.Minimum = rangeRouteConstraint.Min; + schema.Maximum = rangeRouteConstraint.Max.ToString(CultureInfo.InvariantCulture); + schema.Minimum = rangeRouteConstraint.Min.ToString(CultureInfo.InvariantCulture); } private static void ApplyMinRouteConstraint(OpenApiSchema schema, MinRouteConstraint minRouteConstraint) - => schema.Minimum = minRouteConstraint.Min; + => schema.Minimum = minRouteConstraint.Min.ToString(CultureInfo.InvariantCulture); private static void ApplyMaxRouteConstraint(OpenApiSchema schema, MaxRouteConstraint maxRouteConstraint) - => schema.Maximum = maxRouteConstraint.Max; + => schema.Maximum = maxRouteConstraint.Max.ToString(CultureInfo.InvariantCulture); private static void ApplyRegularExpressionAttribute(OpenApiSchema schema, RegularExpressionAttribute regularExpressionAttribute) { diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGenerator.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGenerator.cs index f483d9134e..22d03a45c3 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGenerator.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGenerator.cs @@ -2,11 +2,10 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Reflection; -using System.Text.Json; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -17,7 +16,7 @@ public class SchemaGenerator( private readonly SchemaGeneratorOptions _generatorOptions = generatorOptions; private readonly ISerializerDataContractResolver _serializerDataContractResolver = serializerDataContractResolver; - public OpenApiSchema GenerateSchema( + public IOpenApiSchema GenerateSchema( Type modelType, SchemaRepository schemaRepository, MemberInfo memberInfo = null, @@ -38,7 +37,7 @@ public OpenApiSchema GenerateSchema( } } - private OpenApiSchema GenerateSchemaForMember( + private IOpenApiSchema GenerateSchemaForMember( Type modelType, SchemaRepository schemaRepository, MemberInfo memberInfo, @@ -50,13 +49,15 @@ private OpenApiSchema GenerateSchemaForMember( ? GeneratePolymorphicSchema(schemaRepository, knownTypesDataContracts) : GenerateConcreteSchema(dataContract, schemaRepository); - if (_generatorOptions.UseAllOfToExtendReferenceSchemas && schema.Reference != null) + if (_generatorOptions.UseAllOfToExtendReferenceSchemas && schema is OpenApiSchemaReference reference) { - schema.AllOf = [new OpenApiSchema { Reference = schema.Reference }]; - schema.Reference = null; + schema = new OpenApiSchema() + { + AllOf = [reference], + }; } - if (schema.Reference == null) + if (schema is OpenApiSchema concrete) { var customAttributes = memberInfo.GetInlineAndMetadataAttributes(); @@ -65,23 +66,25 @@ private OpenApiSchema GenerateSchemaForMember( { var requiredAttribute = customAttributes.OfType().FirstOrDefault(); - schema.Nullable = IsNullable(requiredAttribute, dataProperty, memberInfo); + var nullable = IsNullable(requiredAttribute, dataProperty, memberInfo); + + SetNullable(concrete, nullable); - schema.ReadOnly = dataProperty.IsReadOnly; - schema.WriteOnly = dataProperty.IsWriteOnly; - schema.MinLength = modelType == typeof(string) && requiredAttribute is { AllowEmptyStrings: false } ? 1 : null; + concrete.ReadOnly = dataProperty.IsReadOnly; + concrete.WriteOnly = dataProperty.IsWriteOnly; + concrete.MinLength = modelType == typeof(string) && requiredAttribute is { AllowEmptyStrings: false } ? 1 : null; } var defaultValueAttribute = customAttributes.OfType().FirstOrDefault(); if (defaultValueAttribute != null) { - schema.Default = GenerateDefaultValue(dataContract, modelType, defaultValueAttribute.Value); + concrete.Default = GenerateDefaultValue(dataContract, modelType, defaultValueAttribute.Value); } var obsoleteAttribute = customAttributes.OfType().FirstOrDefault(); if (obsoleteAttribute != null) { - schema.Deprecated = true; + concrete.Deprecated = true; } // NullableAttribute behaves differently for Dictionaries @@ -97,9 +100,9 @@ private OpenApiSchema GenerateSchemaForMember( genericTypes.Any(t => t.GetGenericTypeDefinition() == typeof(IDictionary<,>)) || genericTypes.Any(t => t.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)); - if (isDictionaryType) + if (isDictionaryType && schema.AdditionalProperties is OpenApiSchema additionalProperties) { - schema.AdditionalProperties.Nullable = !memberInfo.IsDictionaryValueNonNullable(); + SetNullable(additionalProperties, !memberInfo.IsDictionaryValueNonNullable()); } } @@ -123,7 +126,7 @@ private bool IsNullable(RequiredAttribute requiredAttribute, DataProperty dataPr return nullable; } - private OpenApiSchema GenerateSchemaForParameter( + private IOpenApiSchema GenerateSchemaForParameter( Type modelType, SchemaRepository schemaRepository, ParameterInfo parameterInfo, @@ -135,13 +138,12 @@ private OpenApiSchema GenerateSchemaForParameter( ? GeneratePolymorphicSchema(schemaRepository, knownTypesDataContracts) : GenerateConcreteSchema(dataContract, schemaRepository); - if (_generatorOptions.UseAllOfToExtendReferenceSchemas && schema.Reference != null) + if (_generatorOptions.UseAllOfToExtendReferenceSchemas && schema is OpenApiSchemaReference reference) { - schema.AllOf = [new OpenApiSchema { Reference = schema.Reference }]; - schema.Reference = null; + schema = new OpenApiSchema() { AllOf = [reference] }; } - if (schema.Reference == null) + if (schema is OpenApiSchema concrete) { var customAttributes = parameterInfo.GetCustomAttributes(); @@ -151,7 +153,7 @@ private OpenApiSchema GenerateSchemaForParameter( if (defaultValue != null) { - schema.Default = GenerateDefaultValue(dataContract, modelType, defaultValue); + concrete.Default = GenerateDefaultValue(dataContract, modelType, defaultValue); } schema.ApplyValidationAttributes(customAttributes); @@ -166,7 +168,7 @@ private OpenApiSchema GenerateSchemaForParameter( return schema; } - private OpenApiSchema GenerateSchemaForType(Type modelType, SchemaRepository schemaRepository) + private IOpenApiSchema GenerateSchemaForType(Type modelType, SchemaRepository schemaRepository) { var dataContract = GetDataContractFor(modelType); @@ -174,12 +176,12 @@ private OpenApiSchema GenerateSchemaForType(Type modelType, SchemaRepository sch ? GeneratePolymorphicSchema(schemaRepository, knownTypesDataContracts) : GenerateConcreteSchema(dataContract, schemaRepository); - if (schema.Reference == null) + if (schema is not OpenApiSchemaReference) { ApplyFilters(schema, modelType, schemaRepository); - if (Nullable.GetUnderlyingType(modelType) != null) + if (Nullable.GetUnderlyingType(modelType) != null && schema is OpenApiSchema concrete) { - schema.Nullable = true; + SetNullable(concrete, true); } } @@ -233,9 +235,9 @@ private OpenApiSchema GeneratePolymorphicSchema( typeof(System.IO.Pipelines.PipeReader), ]; - private OpenApiSchema GenerateConcreteSchema(DataContract dataContract, SchemaRepository schemaRepository) + private IOpenApiSchema GenerateConcreteSchema(DataContract dataContract, SchemaRepository schemaRepository) { - if (TryGetCustomTypeMapping(dataContract.UnderlyingType, out Func customSchemaFactory)) + if (TryGetCustomTypeMapping(dataContract.UnderlyingType, out Func customSchemaFactory)) { return customSchemaFactory(); } @@ -294,7 +296,7 @@ private OpenApiSchema GenerateConcreteSchema(DataContract dataContract, SchemaRe : schemaFactory(); } - private bool TryGetCustomTypeMapping(Type modelType, out Func schemaFactory) + private bool TryGetCustomTypeMapping(Type modelType, out Func schemaFactory) { return _generatorOptions.CustomTypeMappings.TryGetValue(modelType, out schemaFactory) || @@ -315,6 +317,14 @@ private static OpenApiSchema CreatePrimitiveSchema(DataContract dataContract) { var enumValues = underlyingType.GetEnumValues().Cast(); + /* + See https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/3428 + if (dataContract.UnderlyingType != underlyingType) + { + SetNullable(schema, true); + enumValues = enumValues.Append(null); + }*/ + schema.Enum = [.. enumValues .Select(value => dataContract.JsonConverter(value)) .Distinct() @@ -368,7 +378,7 @@ private OpenApiSchema CreateObjectSchema(DataContract dataContract, SchemaReposi var schema = new OpenApiSchema { Type = JsonSchemaTypes.Object, - Properties = new Dictionary(), + Properties = new Dictionary(), Required = new SortedSet(), AdditionalPropertiesAllowed = false }; @@ -385,10 +395,12 @@ private OpenApiSchema CreateObjectSchema(DataContract dataContract, SchemaReposi if (_generatorOptions.UseAllOfForInheritance) { root = new OpenApiSchema(); + root.AllOf ??= []; root.AllOf.Add(baseTypeSchema); } else { + schema.AllOf ??= []; schema.AllOf.Add(baseTypeSchema); } @@ -455,6 +467,11 @@ private OpenApiSchema CreateObjectSchema(DataContract dataContract, SchemaReposi root.AllOf.Add(schema); } + if (schema.Required?.Count > 1) + { + schema.Required = new SortedSet(schema.Required); + } + return root; } @@ -503,14 +520,18 @@ private bool TryGetDiscriminatorFor( if (discriminatorValue != null) { - discriminator.Mapping.Add(discriminatorValue, GenerateConcreteSchema(knownTypeDataContract, schemaRepository).Reference.ReferenceV3); + if (GenerateConcreteSchema(knownTypeDataContract, schemaRepository) is OpenApiSchemaReference reference) + { + discriminator.Mapping ??= new Dictionary(); + discriminator.Mapping.Add(discriminatorValue, reference); + } } } return true; } - private OpenApiSchema GenerateReferencedSchema( + private OpenApiSchemaReference GenerateReferencedSchema( DataContract dataContract, SchemaRepository schemaRepository, Func definitionFactory) @@ -532,7 +553,7 @@ private OpenApiSchema GenerateReferencedSchema( } private void ApplyFilters( - OpenApiSchema schema, + IOpenApiSchema schema, Type type, SchemaRepository schemaRepository, MemberInfo memberInfo = null, @@ -551,7 +572,7 @@ private void ApplyFilters( } } - private Microsoft.OpenApi.Any.IOpenApiAny GenerateDefaultValue( + private System.Text.Json.Nodes.JsonNode GenerateDefaultValue( DataContract dataContract, Type modelType, object defaultValue) @@ -571,6 +592,20 @@ private Microsoft.OpenApi.Any.IOpenApiAny GenerateDefaultValue( return JsonModelFactory.CreateFromJson(defaultAsJson); } - private static string FromDataType(DataType dataType) - => dataType.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture); + private static void SetNullable(OpenApiSchema schema, bool nullable) + { + // See https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/3387 + if (nullable) + { + schema.Type ??= JsonSchemaType.Null; + schema.Type |= JsonSchemaType.Null; + } + else if (schema.Type.HasValue) + { + schema.Type &= ~JsonSchemaType.Null; + } + } + + private static JsonSchemaType FromDataType(DataType dataType) => + Enum.Parse(dataType.ToString()); } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGeneratorOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGeneratorOptions.cs index dd12f4dba3..1ce3a270f0 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGeneratorOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/SchemaGeneratorOptions.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -6,7 +6,7 @@ public class SchemaGeneratorOptions { public SchemaGeneratorOptions() { - CustomTypeMappings = new Dictionary>(); + CustomTypeMappings = new Dictionary>(); SchemaIdSelector = DefaultSchemaIdSelector; SubTypesSelector = DefaultSubTypesSelector; DiscriminatorNameSelector = DefaultDiscriminatorNameSelector; @@ -14,7 +14,7 @@ public SchemaGeneratorOptions() SchemaFilters = []; } - public IDictionary> CustomTypeMappings { get; set; } + public IDictionary> CustomTypeMappings { get; set; } public bool UseInlineDefinitionsForEnums { get; set; } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentAsyncFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentAsyncFilter.cs index 48c4753450..eabf06e659 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentAsyncFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentAsyncFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentFilter.cs index 40c087d5d9..34709b12d9 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IDocumentFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationAsyncFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationAsyncFilter.cs index 59ace9898f..34a51a0dbf 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationAsyncFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationAsyncFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationFilter.cs index 44b280e74c..d03c299388 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IOperationFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterAsyncFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterAsyncFilter.cs index 8294a08462..3512c98759 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterAsyncFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterAsyncFilter.cs @@ -1,8 +1,8 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; public interface IParameterAsyncFilter { - Task ApplyAsync(OpenApiParameter parameter, ParameterFilterContext context, CancellationToken cancellationToken); + Task ApplyAsync(IOpenApiParameter parameter, ParameterFilterContext context, CancellationToken cancellationToken); } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterFilter.cs index 636ea14893..0bcd3d264d 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IParameterFilter.cs @@ -1,8 +1,8 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; public interface IParameterFilter { - void Apply(OpenApiParameter parameter, ParameterFilterContext context); + void Apply(IOpenApiParameter parameter, ParameterFilterContext context); } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyAsyncFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyAsyncFilter.cs index a7019626a2..b7f95a506b 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyAsyncFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyAsyncFilter.cs @@ -1,8 +1,8 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; public interface IRequestBodyAsyncFilter { - Task ApplyAsync(OpenApiRequestBody requestBody, RequestBodyFilterContext context, CancellationToken cancellationToken); + Task ApplyAsync(IOpenApiRequestBody requestBody, RequestBodyFilterContext context, CancellationToken cancellationToken); } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyFilter.cs index e26acb75b3..7d379bd982 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/IRequestBodyFilter.cs @@ -1,8 +1,8 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; public interface IRequestBodyFilter { - void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context); + void Apply(IOpenApiRequestBody requestBody, RequestBodyFilterContext context); } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ISchemaGenerator.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ISchemaGenerator.cs index 5c0181f2be..993b6114c4 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ISchemaGenerator.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ISchemaGenerator.cs @@ -1,12 +1,12 @@ using System.Reflection; -using Microsoft.OpenApi.Models; using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; public interface ISchemaGenerator { - OpenApiSchema GenerateSchema( + IOpenApiSchema GenerateSchema( Type modelType, SchemaRepository schemaRepository, MemberInfo memberInfo = null, diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/OpenApiAnyFactory.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/OpenApiAnyFactory.cs deleted file mode 100644 index 32cb72909b..0000000000 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/OpenApiAnyFactory.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Text.Json; -using Microsoft.OpenApi.Any; - -namespace Swashbuckle.AspNetCore.SwaggerGen; - -public static class OpenApiAnyFactory -{ - public static IOpenApiAny CreateFromJson(string json) - => CreateFromJson(json, null); - - public static IOpenApiAny CreateFromJson(string json, JsonSerializerOptions options) - { - if (json is null) - { - return null; - } - - try - { - var element = JsonSerializer.Deserialize(json, options); - return CreateFromJsonElement(element); - } - catch (Exception) - { - return null; - } - } - - private static OpenApiArray CreateOpenApiArray(JsonElement jsonElement) - { - var openApiArray = new OpenApiArray(); - - foreach (var item in jsonElement.EnumerateArray()) - { - openApiArray.Add(CreateFromJsonElement(item)); - } - - return openApiArray; - } - - private static OpenApiObject CreateOpenApiObject(JsonElement jsonElement) - { - var openApiObject = new OpenApiObject(); - - foreach (var property in jsonElement.EnumerateObject()) - { - openApiObject.Add(property.Name, CreateFromJsonElement(property.Value)); - } - - return openApiObject; - } - - private static IOpenApiAny CreateFromJsonElement(JsonElement jsonElement) - { - if (jsonElement.ValueKind == JsonValueKind.Null) - { - return new OpenApiNull(); - } - - if (jsonElement.ValueKind == JsonValueKind.True || jsonElement.ValueKind == JsonValueKind.False) - { - return new OpenApiBoolean(jsonElement.GetBoolean()); - } - - if (jsonElement.ValueKind == JsonValueKind.Number) - { - if (jsonElement.TryGetInt32(out int intValue)) - { - return new OpenApiInteger(intValue); - } - - if (jsonElement.TryGetInt64(out long longValue)) - { - return new OpenApiLong(longValue); - } - - if (jsonElement.TryGetSingle(out float floatValue) && !float.IsInfinity(floatValue)) - { - return new OpenApiFloat(floatValue); - } - - if (jsonElement.TryGetDouble(out double doubleValue)) - { - return new OpenApiDouble(doubleValue); - } - } - - if (jsonElement.ValueKind == JsonValueKind.String) - { - return new OpenApiString(jsonElement.ToString()); - } - - if (jsonElement.ValueKind == JsonValueKind.Array) - { - return CreateOpenApiArray(jsonElement); - } - - if (jsonElement.ValueKind == JsonValueKind.Object) - { - return CreateOpenApiObject(jsonElement); - } - - throw new ArgumentException($"Unsupported value kind {jsonElement.ValueKind}"); - } -} diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/OperationFilterContext.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/OperationFilterContext.cs index e71059c169..daa3e312e9 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/OperationFilterContext.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/OperationFilterContext.cs @@ -1,5 +1,6 @@ using System.Reflection; using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -7,6 +8,7 @@ public class OperationFilterContext( ApiDescription apiDescription, ISchemaGenerator schemaRegistry, SchemaRepository schemaRepository, + OpenApiDocument document, MethodInfo methodInfo) { public ApiDescription ApiDescription { get; } = apiDescription; @@ -17,5 +19,7 @@ public class OperationFilterContext( public MethodInfo MethodInfo { get; } = methodInfo; + public OpenApiDocument Document { get; } = document; + public string DocumentName => SchemaRepository.DocumentName; } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ParameterFilterContext.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ParameterFilterContext.cs index 7defd60774..6c951bc874 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ParameterFilterContext.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/ParameterFilterContext.cs @@ -1,5 +1,6 @@ using System.Reflection; using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -7,6 +8,7 @@ public class ParameterFilterContext( ApiParameterDescription apiParameterDescription, ISchemaGenerator schemaGenerator, SchemaRepository schemaRepository, + OpenApiDocument document, PropertyInfo propertyInfo = null, ParameterInfo parameterInfo = null) { @@ -20,5 +22,7 @@ public class ParameterFilterContext( public ParameterInfo ParameterInfo { get; } = parameterInfo; + public OpenApiDocument Document { get; } = document; + public string DocumentName => SchemaRepository.DocumentName; } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/RequestBodyFilterContext.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/RequestBodyFilterContext.cs index fd01cd3552..d9beeb9244 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/RequestBodyFilterContext.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/RequestBodyFilterContext.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -6,7 +7,8 @@ public class RequestBodyFilterContext( ApiParameterDescription bodyParameterDescription, IEnumerable formParameterDescriptions, ISchemaGenerator schemaGenerator, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { public ApiParameterDescription BodyParameterDescription { get; } = bodyParameterDescription; @@ -16,5 +18,7 @@ public class RequestBodyFilterContext( public SchemaRepository SchemaRepository { get; } = schemaRepository; + public OpenApiDocument Document { get; } = document; + public string DocumentName => SchemaRepository.DocumentName; } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SchemaRepository.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SchemaRepository.cs index 82753cc036..537e29bf02 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SchemaRepository.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SchemaRepository.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -8,7 +8,7 @@ public class SchemaRepository(string documentName = null) public string DocumentName { get; } = documentName; - public Dictionary Schemas { get; private set; } = []; + public Dictionary Schemas { get; private set; } = []; public void RegisterType(Type type, string schemaId) { @@ -24,14 +24,11 @@ public void RegisterType(Type type, string schemaId) _reservedIds.Add(type, schemaId); } - public bool TryLookupByType(Type type, out OpenApiSchema referenceSchema) + public bool TryLookupByType(Type type, out OpenApiSchemaReference referenceSchema) { if (_reservedIds.TryGetValue(type, out string schemaId)) { - referenceSchema = new OpenApiSchema - { - Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = schemaId } - }; + referenceSchema = new OpenApiSchemaReference(schemaId); return true; } @@ -39,13 +36,10 @@ public bool TryLookupByType(Type type, out OpenApiSchema referenceSchema) return false; } - public OpenApiSchema AddDefinition(string schemaId, OpenApiSchema schema) + public OpenApiSchemaReference AddDefinition(string schemaId, OpenApiSchema schema) { Schemas.Add(schemaId, schema); - return new OpenApiSchema - { - Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = schemaId } - }; + return new OpenApiSchemaReference(schemaId); } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs index 55c44f9c3d..11e16c8e48 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Swagger; @@ -39,13 +39,19 @@ public async Task GetSwaggerAsync( var (filterContext, document) = GetSwaggerDocumentWithoutPaths(documentName, host, basePath); document.Paths = await GeneratePathsAsync(document, filterContext.ApiDescriptions, filterContext.SchemaRepository); - document.Components.SecuritySchemes = await GetSecuritySchemesAsync(); + + // See https://github.com/microsoft/OpenAPI.NET/issues/2300#issuecomment-2775307399 + foreach (var scheme in await GetSecuritySchemesAsync()) + { + document.AddComponent(scheme.Key, scheme.Value); + } if (_options.SecurityRequirements is { Count: > 0 } requirements) { foreach (var requirement in requirements) { - document.SecurityRequirements.Add(requirement); + document.Security ??= []; + document.Security.Add(requirement(document)); } } @@ -59,7 +65,7 @@ public async Task GetSwaggerAsync( filter.Apply(document, filterContext); } - SortSchemas(document); + SortDocument(document); return document; } @@ -71,13 +77,18 @@ public OpenApiDocument GetSwagger(string documentName, string host = null, strin var (filterContext, document) = GetSwaggerDocumentWithoutPaths(documentName, host, basePath); document.Paths = GeneratePaths(document, filterContext.ApiDescriptions, filterContext.SchemaRepository); - document.Components.SecuritySchemes = GetSecuritySchemesAsync().Result; + + // See https://github.com/microsoft/OpenAPI.NET/issues/2300#issuecomment-2775307399 + foreach (var scheme in GetSecuritySchemesAsync().Result) + { + document.AddComponent(scheme.Key, scheme.Value); + } if (_options.SecurityRequirements is { Count: > 0 } requirements) { foreach (var requirement in requirements) { - document.SecurityRequirements.Add(requirement); + document.Security.Add(requirement(document)); } } @@ -86,7 +97,7 @@ public OpenApiDocument GetSwagger(string documentName, string host = null, strin filter.Apply(document, filterContext); } - SortSchemas(document); + SortDocument(document); return document; } @@ -113,9 +124,9 @@ public OpenApiDocument GetSwagger(string documentName, string host = null, strin public IList GetDocumentNames() => [.. _options.SwaggerDocs.Keys]; - private void SortSchemas(OpenApiDocument document) + private void SortDocument(OpenApiDocument document) { - document.Components.Schemas = new SortedDictionary(document.Components.Schemas, _options.SchemaComparer); + document.Components.Schemas = new SortedDictionary(document.Components.Schemas, _options.SchemaComparer); } private (DocumentFilterContext, OpenApiDocument) GetSwaggerDocumentWithoutPaths(string documentName, string host = null, string basePath = null) @@ -150,11 +161,11 @@ private void SortSchemas(OpenApiDocument document) return (new DocumentFilterContext(applicableApiDescriptions, _schemaGenerator, schemaRepository), swaggerDoc); } - private async Task> GetSecuritySchemesAsync() + private async Task> GetSecuritySchemesAsync() { if (!_options.InferSecuritySchemes) { - return new Dictionary(_options.SecuritySchemes); + return new Dictionary(_options.SecuritySchemes); } var authenticationSchemes = (_authenticationSchemeProvider is not null) @@ -177,7 +188,7 @@ private async Task> GetSecurityScheme Scheme = "bearer", // "bearer" refers to the header name here In = ParameterLocation.Header, BearerFormat = "Json Web Token" - }); + } as IOpenApiSecurityScheme); } private List GenerateServers(string host, string basePath) @@ -196,7 +207,7 @@ private async Task GeneratePathsAsync( OpenApiDocument document, IEnumerable apiDescriptions, SchemaRepository schemaRepository, - Func, SchemaRepository, Task>> operationsGenerator) + Func, SchemaRepository, Task>> operationsGenerator) { var apiDescriptionsByPath = apiDescriptions .OrderBy(_options.SortKeySelector) @@ -211,7 +222,7 @@ private async Task GeneratePathsAsync( { Operations = await operationsGenerator(document, group, schemaRepository) }); - }; + } return paths; } @@ -240,7 +251,7 @@ private async Task GeneratePathsAsync( GenerateOperationsAsync); } - private IEnumerable<(OperationType, ApiDescription)> GetOperationsGroupedByMethod( + private IEnumerable<(HttpMethod, ApiDescription)> GetOperationsGroupedByMethod( IEnumerable apiDescriptions) { return apiDescriptions @@ -249,13 +260,13 @@ private async Task GeneratePathsAsync( .Select(PrepareGenerateOperation); } - private Dictionary GenerateOperations( + private Dictionary GenerateOperations( OpenApiDocument document, IEnumerable apiDescriptions, SchemaRepository schemaRepository) { var apiDescriptionsByMethod = GetOperationsGroupedByMethod(apiDescriptions); - var operations = new Dictionary(); + var operations = new Dictionary(); foreach ((var operationType, var description) in apiDescriptionsByMethod) { @@ -265,13 +276,13 @@ private Dictionary GenerateOperations( return operations; } - private async Task> GenerateOperationsAsync( + private async Task> GenerateOperationsAsync( OpenApiDocument document, IEnumerable apiDescriptions, SchemaRepository schemaRepository) { var apiDescriptionsByMethod = GetOperationsGroupedByMethod(apiDescriptions); - var operations = new Dictionary(); + var operations = new Dictionary(); foreach ((var operationType, var description) in apiDescriptionsByMethod) { @@ -281,7 +292,7 @@ private async Task> GenerateOperatio return operations; } - private (OperationType OperationType, ApiDescription ApiDescription) PrepareGenerateOperation(IGrouping group) + private (HttpMethod OperationType, ApiDescription ApiDescription) PrepareGenerateOperation(IGrouping group) { var httpMethod = group.Key ?? throw new SwaggerGeneratorException(string.Format( "Ambiguous HTTP method for action - {0}. " + @@ -319,11 +330,11 @@ private async Task GenerateOperationAsync( OpenApiDocument document, ApiDescription apiDescription, SchemaRepository schemaRepository, - Func>> parametersGenerator, - Func> bodyGenerator, + Func>> parametersGenerator, + Func> bodyGenerator, Func applyFilters) { - var operation = await GenerateOpenApiOperationFromMetadataAsync(apiDescription, schemaRepository); + var operation = await GenerateOpenApiOperationFromMetadataAsync(apiDescription, schemaRepository, document); try { @@ -331,8 +342,8 @@ private async Task GenerateOperationAsync( { Tags = GenerateOperationTags(document, apiDescription), OperationId = _options.OperationIdSelector(apiDescription), - Parameters = await parametersGenerator(apiDescription, schemaRepository), - RequestBody = await bodyGenerator(apiDescription, schemaRepository), + Parameters = await parametersGenerator(apiDescription, schemaRepository, document), + RequestBody = await bodyGenerator(apiDescription, schemaRepository, document), Responses = GenerateResponses(apiDescription, schemaRepository), Deprecated = apiDescription.CustomAttributes().OfType().Any(), Summary = GenerateSummary(apiDescription), @@ -340,7 +351,7 @@ private async Task GenerateOperationAsync( }; apiDescription.TryGetMethodInfo(out MethodInfo methodInfo); - var filterContext = new OperationFilterContext(apiDescription, _schemaGenerator, schemaRepository, methodInfo); + var filterContext = new OperationFilterContext(apiDescription, _schemaGenerator, schemaRepository, document, methodInfo); await applyFilters(operation, filterContext); @@ -360,8 +371,8 @@ private OpenApiOperation GenerateOperation(OpenApiDocument document, ApiDescript document, apiDescription, schemaRepository, - (description, repository) => Task.FromResult(GenerateParameters(description, repository)), - (description, repository) => Task.FromResult(GenerateRequestBody(description, repository)), + (description, repository, document) => Task.FromResult(GenerateParameters(description, repository, document)), + (description, repository, document) => Task.FromResult(GenerateRequestBody(description, repository, document)), (operation, filterContext) => { foreach (var filter in _options.OperationFilters) @@ -398,7 +409,10 @@ private async Task GenerateOperationAsync( }); } - private async Task GenerateOpenApiOperationFromMetadataAsync(ApiDescription apiDescription, SchemaRepository schemaRepository) + private async Task GenerateOpenApiOperationFromMetadataAsync( + ApiDescription apiDescription, + SchemaRepository schemaRepository, + OpenApiDocument document) { var metadata = apiDescription.ActionDescriptor?.EndpointMetadata; var operation = metadata?.OfType().SingleOrDefault(); @@ -409,14 +423,19 @@ private async Task GenerateOpenApiOperationFromMetadataAsync(A } // Schemas will be generated via Swashbuckle by default. - foreach (var parameter in operation.Parameters) + foreach (var parameter in operation.Parameters ?? []) { var apiParameter = apiDescription.ParameterDescriptions.SingleOrDefault((p) => p.Name == parameter.Name && !p.IsFromBody() && !p.IsFromForm() && !p.IsIllegalHeaderParameter()); if (apiParameter is not null) { - var (parameterAndContext, filterContext) = GenerateParameterAndContext(apiParameter, schemaRepository); - parameter.Name = parameterAndContext.Name; - parameter.Schema = parameterAndContext.Schema; + var (parameterAndContext, filterContext) = GenerateParameterAndContext(apiParameter, schemaRepository, document); + + if (parameter is OpenApiParameter concrete) + { + concrete.Name = parameterAndContext.Name; + concrete.Schema = parameterAndContext.Schema; + } + parameter.Description ??= parameterAndContext.Description; foreach (var filter in _options.ParameterAsyncFilters) @@ -469,7 +488,8 @@ private async Task GenerateOpenApiOperationFromMetadataAsync(A bodyParameterDescription: bodyParameterDescription, formParameterDescriptions: bodyParameterDescription is null ? fromFormParameters : null, schemaGenerator: _schemaGenerator, - schemaRepository: schemaRepository); + schemaRepository: schemaRepository, + document); foreach (var filter in _options.RequestBodyAsyncFilters) { @@ -484,18 +504,21 @@ private async Task GenerateOpenApiOperationFromMetadataAsync(A } } - foreach (var kvp in operation.Responses) + if (operation.Responses is { Count: > 0 } responses) { - var response = kvp.Value; - var responseModel = apiDescription.SupportedResponseTypes.SingleOrDefault((p) => p.StatusCode.ToString() == kvp.Key); - if (responseModel is not null) + foreach (var kvp in responses) { - var responseContentTypes = response?.Content?.Values; - if (responseContentTypes is not null) + var response = kvp.Value; + var responseModel = apiDescription.SupportedResponseTypes.SingleOrDefault((p) => p.StatusCode.ToString() == kvp.Key); + if (responseModel is not null) { - foreach (var content in responseContentTypes) + var responseContentTypes = response?.Content?.Values; + if (responseContentTypes is not null) { - content.Schema = GenerateSchema(responseModel.Type, schemaRepository); + foreach (var content in responseContentTypes) + { + content.Schema = GenerateSchema(responseModel.Type, schemaRepository); + } } } } @@ -504,13 +527,31 @@ private async Task GenerateOpenApiOperationFromMetadataAsync(A return operation; } - private List GenerateOperationTags(OpenApiDocument document, ApiDescription apiDescription) - => [.. _options.TagsSelector(apiDescription).Select(tagName => CreateTag(tagName, document))]; + private HashSet GenerateOperationTags(OpenApiDocument document, ApiDescription apiDescription) + { + // The tags must be present at the document level for the tag references + // to be serialized correctly at the operation level, so we need to add + // them to the document before adding the references to the operation. + // See https://github.com/microsoft/OpenAPI.NET/issues/2319. + string[] names = [.. _options.TagsSelector(apiDescription)]; + + if (names.Length > 0) + { + document.Tags ??= new HashSet(); + foreach (var name in names) + { + document.Tags.Add(new OpenApiTag { Name = name }); + } + } + + return [.. names.Select((name) => new OpenApiTagReference(name, document))]; + } - private static async Task> GenerateParametersAsync( + private static async Task> GenerateParametersAsync( ApiDescription apiDescription, SchemaRepository schemaRepository, - Func> parameterGenerator) + OpenApiDocument document, + Func> parameterGenerator) { if (apiDescription.ParameterDescriptions.Any(IsFromFormAttributeUsedWithIFormFile)) { @@ -530,31 +571,37 @@ private static async Task> GenerateParametersAsync( && !apiParam.IsIllegalHeaderParameter(); }); - var parameters = new List(); + var parameters = new List(); foreach (var parameter in applicableApiParameters) { - parameters.Add(await parameterGenerator(parameter, schemaRepository)); + parameters.Add(await parameterGenerator(parameter, schemaRepository, document)); } return parameters; } - private List GenerateParameters(ApiDescription apiDescription, SchemaRepository schemaRepository) + private List GenerateParameters( + ApiDescription apiDescription, + SchemaRepository schemaRepository, + OpenApiDocument document) { return GenerateParametersAsync( apiDescription, schemaRepository, - (parameter, schemaRepository) => Task.FromResult(GenerateParameter(parameter, schemaRepository))).Result; + document, + (parameter, schemaRepository, document) => Task.FromResult(GenerateParameter(parameter, schemaRepository, document))).Result; } - private async Task> GenerateParametersAsync( + private async Task> GenerateParametersAsync( ApiDescription apiDescription, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { return await GenerateParametersAsync( apiDescription, schemaRepository, + document, GenerateParameterAsync); } @@ -595,8 +642,9 @@ apiParameter.Type is not null && var description = schema.Description; if (string.IsNullOrEmpty(description) && - !string.IsNullOrEmpty(schema?.Reference?.Id) && - schemaRepository.Schemas.TryGetValue(schema.Reference.Id, out var openApiSchema)) + schema is OpenApiSchemaReference reference && + !string.IsNullOrEmpty(reference.Reference.Id) && + schemaRepository.Schemas.TryGetValue(reference.Reference.Id, out var openApiSchema)) { description = openApiSchema.Description; } @@ -624,7 +672,8 @@ apiParameter.Type is not null && private (OpenApiParameter, ParameterFilterContext) GenerateParameterAndContext( ApiParameterDescription apiParameter, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { var parameter = GenerateParameterWithoutFilter(apiParameter, schemaRepository); @@ -632,6 +681,7 @@ apiParameter.Type is not null && apiParameter, _schemaGenerator, schemaRepository, + document, apiParameter.PropertyInfo(), apiParameter.ParameterInfo()); @@ -640,9 +690,10 @@ apiParameter.Type is not null && private OpenApiParameter GenerateParameter( ApiParameterDescription apiParameter, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { - var (parameter, filterContext) = GenerateParameterAndContext(apiParameter, schemaRepository); + var (parameter, filterContext) = GenerateParameterAndContext(apiParameter, schemaRepository, document); foreach (var filter in _options.ParameterFilters) { @@ -654,9 +705,10 @@ private OpenApiParameter GenerateParameter( private async Task GenerateParameterAsync( ApiParameterDescription apiParameter, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { - var (parameter, filterContext) = GenerateParameterAndContext(apiParameter, schemaRepository); + var (parameter, filterContext) = GenerateParameterAndContext(apiParameter, schemaRepository, document); foreach (var filter in _options.ParameterAsyncFilters) { @@ -671,7 +723,7 @@ private async Task GenerateParameterAsync( return parameter; } - private OpenApiSchema GenerateSchema( + private IOpenApiSchema GenerateSchema( Type type, SchemaRepository schemaRepository, PropertyInfo propertyInfo = null, @@ -690,9 +742,10 @@ private OpenApiSchema GenerateSchema( } } - private (OpenApiRequestBody RequestBody, RequestBodyFilterContext FilterContext) GenerateRequestBodyAndFilterContext( + private (IOpenApiRequestBody RequestBody, RequestBodyFilterContext FilterContext) GenerateRequestBodyAndFilterContext( ApiDescription apiDescription, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { OpenApiRequestBody requestBody = null; RequestBodyFilterContext filterContext = null; @@ -712,7 +765,8 @@ private OpenApiSchema GenerateSchema( bodyParameterDescription: bodyParameter, formParameterDescriptions: null, schemaGenerator: _schemaGenerator, - schemaRepository: schemaRepository); + schemaRepository: schemaRepository, + document); } else if (formParameters.Count > 0) { @@ -722,17 +776,19 @@ private OpenApiSchema GenerateSchema( bodyParameterDescription: null, formParameterDescriptions: formParameters, schemaGenerator: _schemaGenerator, - schemaRepository: schemaRepository); + schemaRepository: schemaRepository, + document); } return (requestBody, filterContext); } - private OpenApiRequestBody GenerateRequestBody( + private IOpenApiRequestBody GenerateRequestBody( ApiDescription apiDescription, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { - var (requestBody, filterContext) = GenerateRequestBodyAndFilterContext(apiDescription, schemaRepository); + var (requestBody, filterContext) = GenerateRequestBodyAndFilterContext(apiDescription, schemaRepository, document); if (requestBody != null) { @@ -745,11 +801,12 @@ private OpenApiRequestBody GenerateRequestBody( return requestBody; } - private async Task GenerateRequestBodyAsync( + private async Task GenerateRequestBodyAsync( ApiDescription apiDescription, - SchemaRepository schemaRepository) + SchemaRepository schemaRepository, + OpenApiDocument document) { - var (requestBody, filterContext) = GenerateRequestBodyAndFilterContext(apiDescription, schemaRepository); + var (requestBody, filterContext) = GenerateRequestBodyAndFilterContext(apiDescription, schemaRepository, document); if (requestBody != null) { @@ -848,13 +905,13 @@ private OpenApiRequestBody GenerateRequestBodyFromFormParameters( }; } - private OpenApiSchema GenerateSchemaFromFormParameters( + private IOpenApiSchema GenerateSchemaFromFormParameters( IEnumerable formParameters, SchemaRepository schemaRepository) { - var properties = new Dictionary(); + var properties = new Dictionary(); var requiredPropertyNames = new List(); - var ownSchemas = new List(); + var ownSchemas = new List(); foreach (var formParameter in formParameters) { @@ -870,7 +927,7 @@ private OpenApiSchema GenerateSchemaFromFormParameters( formParameter.ParameterInfo()) : new OpenApiSchema { Type = JsonSchemaTypes.String }; - if (schema.Reference is null || + if (schema is not OpenApiSchemaReference || (formParameter.ModelMetadata?.ModelType is not null && (Nullable.GetUnderlyingType(formParameter.ModelMetadata.ModelType) ?? formParameter.ModelMetadata.ModelType).IsEnum)) { var name = _options.DescribeAllParametersInCamelCase @@ -917,12 +974,12 @@ private OpenApiSchema GenerateSchemaFromFormParameters( return GenerateSchemaForProperties(properties, requiredPropertyNames); - static OpenApiSchema GenerateSchemaForProperties(Dictionary properties, List requiredPropertyNames) => + static OpenApiSchema GenerateSchemaForProperties(Dictionary properties, List requiredPropertyNames) => new() { Type = JsonSchemaTypes.Object, Properties = properties, - Required = new SortedSet(requiredPropertyNames) + Required = new SortedSet(requiredPropertyNames), }; } @@ -948,9 +1005,18 @@ private OpenApiResponse GenerateResponse( string statusCode, ApiResponseType apiResponseType) { - var description = ResponseDescriptionMap - .FirstOrDefault((entry) => Regex.IsMatch(statusCode, entry.Key)) - .Value; + string description = null; + +#if NET10_0_OR_GREATER + description = apiResponseType.Description; +#endif + + if (string.IsNullOrEmpty(description)) + { + description = ResponseDescriptionMap + .FirstOrDefault((entry) => Regex.IsMatch(statusCode, entry.Key)) + .Value; + } var responseContentTypes = InferResponseContentTypes(apiDescription, apiResponseType); @@ -1005,16 +1071,16 @@ private static bool IsFromFormAttributeUsedWithIFormFile(ApiParameterDescription return fromFormAttribute != null && parameterInfo?.ParameterType == typeof(IFormFile); } - private static readonly Dictionary OperationTypeMap = new(StringComparer.OrdinalIgnoreCase) + private static readonly Dictionary OperationTypeMap = new(StringComparer.OrdinalIgnoreCase) { - ["GET"] = OperationType.Get, - ["PUT"] = OperationType.Put, - ["POST"] = OperationType.Post, - ["DELETE"] = OperationType.Delete, - ["OPTIONS"] = OperationType.Options, - ["HEAD"] = OperationType.Head, - ["PATCH"] = OperationType.Patch, - ["TRACE"] = OperationType.Trace, + ["GET"] = HttpMethod.Get, + ["PUT"] = HttpMethod.Put, + ["POST"] = HttpMethod.Post, + ["DELETE"] = HttpMethod.Delete, + ["OPTIONS"] = HttpMethod.Options, + ["HEAD"] = HttpMethod.Head, + ["PATCH"] = HttpMethod.Patch, + ["TRACE"] = HttpMethod.Trace, }; private static readonly Dictionary ParameterLocationMap = new() @@ -1117,7 +1183,4 @@ private static string GenerateDescription(ApiDescription apiDescription) => ?.OfType() .Select((p) => p.Description) .LastOrDefault(); - - private static OpenApiTag CreateTag(string name, OpenApiDocument _) => - new() { Name = name }; } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGeneratorOptions.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGeneratorOptions.cs index 38da942d54..ba659c64ae 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGeneratorOptions.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGeneratorOptions.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Routing; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; @@ -19,7 +19,7 @@ public SwaggerGeneratorOptions() SecuritySchemesSelector = null; SchemaComparer = StringComparer.Ordinal; Servers = []; - SecuritySchemes = new Dictionary(); + SecuritySchemes = new Dictionary(); SecurityRequirements = []; ParameterFilters = []; ParameterAsyncFilters = []; @@ -49,15 +49,15 @@ public SwaggerGeneratorOptions() public bool InferSecuritySchemes { get; set; } - public Func, IDictionary> SecuritySchemesSelector { get; set; } + public Func, IDictionary> SecuritySchemesSelector { get; set; } public bool DescribeAllParametersInCamelCase { get; set; } public List Servers { get; set; } - public IDictionary SecuritySchemes { get; set; } + public IDictionary SecuritySchemes { get; set; } - public IList SecurityRequirements { get; set; } + public IList> SecurityRequirements { get; set; } public IComparer SchemaComparer { get; set; } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsDocumentFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsDocumentFilter.cs index a7f5c17a13..8fcd3540c5 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsDocumentFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsDocumentFilter.cs @@ -1,31 +1,15 @@ using System.Xml.XPath; using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; -public class XmlCommentsDocumentFilter : IDocumentFilter +public class XmlCommentsDocumentFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) : IDocumentFilter { private const string SummaryTag = "summary"; - private readonly IReadOnlyDictionary _xmlDocMembers; - private readonly SwaggerGeneratorOptions _options; - - public XmlCommentsDocumentFilter(XPathDocument xmlDoc) - : this(xmlDoc, null) - { - } - - public XmlCommentsDocumentFilter(XPathDocument xmlDoc, SwaggerGeneratorOptions options) - : this(XmlCommentsDocumentHelper.CreateMemberDictionary(xmlDoc), options) - { - } - - internal XmlCommentsDocumentFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) - { - _xmlDocMembers = xmlDocMembers; - _options = options; - } + private readonly IReadOnlyDictionary _xmlDocMembers = xmlDocMembers; + private readonly SwaggerGeneratorOptions _options = options; public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { @@ -48,13 +32,18 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) var summaryNode = typeNode.SelectFirstChild(SummaryTag); if (summaryNode != null) { - swaggerDoc.Tags ??= []; + swaggerDoc.Tags ??= new HashSet(); - swaggerDoc.Tags.Add(new OpenApiTag + var name = nameAndType.Key; + var tag = swaggerDoc.Tags.FirstOrDefault((p) => p?.Name == name); + + if (tag is null) { - Name = nameAndType.Key, - Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml, _options?.XmlCommentEndOfLine) - }); + tag = new() { Name = name }; + swaggerDoc.Tags.Add(tag); + } + + tag.Description ??= XmlCommentsTextHelper.Humanize(summaryNode.InnerXml, _options?.XmlCommentEndOfLine); } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsExampleHelper.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsExampleHelper.cs index 759988f1b0..e85b6cdab1 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsExampleHelper.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsExampleHelper.cs @@ -1,23 +1,37 @@ using System.Text.Json; -using Microsoft.OpenApi.Models; +using System.Text.Json.Nodes; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; internal static class XmlCommentsExampleHelper { - public static Microsoft.OpenApi.Any.IOpenApiAny Create( + public static JsonNode Create( SchemaRepository schemaRepository, - OpenApiSchema schema, + IOpenApiSchema schema, string exampleString) { - var isStringType = - schema?.ResolveType(schemaRepository) == JsonSchemaTypes.String && - !string.Equals(exampleString, "null"); + var type = schema?.ResolveType(schemaRepository); - var exampleAsJson = isStringType - ? JsonSerializer.Serialize(exampleString) - : exampleString; + var isStringType = type is { } value && + value.HasFlag(JsonSchemaType.String) && + !value.HasFlag(JsonSchemaType.Null); - return JsonModelFactory.CreateFromJson(exampleAsJson); + if (isStringType) + { + return JsonValue.Create(exampleString); + } + + // HACK If the value is a string, but we can't detect it as one, then + // if parsing it fails, assume it is a string that isn't quoted. There's + // probably a much better way to deal with this scenario. + try + { + return JsonModelFactory.CreateFromJson(exampleString); + } + catch (JsonException) when (exampleString?.StartsWith('"') == false) + { + return JsonValue.Create(exampleString); + } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsOperationFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsOperationFilter.cs index 4db7b72636..ceb13a22f3 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsOperationFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsOperationFilter.cs @@ -1,26 +1,13 @@ using System.Reflection; using System.Xml.XPath; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; -public class XmlCommentsOperationFilter : IOperationFilter +public class XmlCommentsOperationFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) : IOperationFilter { - private readonly IReadOnlyDictionary _xmlDocMembers; - private readonly SwaggerGeneratorOptions _options; - - public XmlCommentsOperationFilter(XPathDocument xmlDoc) - : this(XmlCommentsDocumentHelper.CreateMemberDictionary(xmlDoc), null) - { - } - - [ActivatorUtilitiesConstructor] - internal XmlCommentsOperationFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) - { - _xmlDocMembers = xmlDocMembers; - _options = options; - } + private readonly IReadOnlyDictionary _xmlDocMembers = xmlDocMembers; + private readonly SwaggerGeneratorOptions _options = options; public void Apply(OpenApiOperation operation, OperationFilterContext context) { diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs index 8139eae9dc..441b7e8e9d 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsParameterFilter.cs @@ -1,28 +1,15 @@ using System.Reflection; using System.Xml.XPath; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; -public class XmlCommentsParameterFilter : IParameterFilter +public class XmlCommentsParameterFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) : IParameterFilter { - private readonly IReadOnlyDictionary _xmlDocMembers; - private readonly SwaggerGeneratorOptions _options; + private readonly IReadOnlyDictionary _xmlDocMembers = xmlDocMembers; + private readonly SwaggerGeneratorOptions _options = options; - public XmlCommentsParameterFilter(XPathDocument xmlDoc) - : this(XmlCommentsDocumentHelper.CreateMemberDictionary(xmlDoc), null) - { - } - - [ActivatorUtilitiesConstructor] - internal XmlCommentsParameterFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) - { - _xmlDocMembers = xmlDocMembers; - _options = options; - } - - public void Apply(OpenApiParameter parameter, ParameterFilterContext context) + public void Apply(IOpenApiParameter parameter, ParameterFilterContext context) { if (context.PropertyInfo != null) { @@ -34,7 +21,7 @@ public void Apply(OpenApiParameter parameter, ParameterFilterContext context) } } - private void ApplyPropertyTags(OpenApiParameter parameter, ParameterFilterContext context) + private void ApplyPropertyTags(IOpenApiParameter parameter, ParameterFilterContext context) { var propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(context.PropertyInfo); @@ -47,14 +34,17 @@ private void ApplyPropertyTags(OpenApiParameter parameter, ParameterFilterContex parameter.Schema.Description = null; // No need to duplicate } - var exampleNode = propertyNode.SelectFirstChild("example"); - if (exampleNode != null) + if (parameter is OpenApiParameter concrete) { - parameter.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, parameter.Schema, exampleNode.ToString()); + var exampleNode = propertyNode.SelectFirstChild("example"); + if (exampleNode != null) + { + concrete.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, parameter.Schema, exampleNode.ToString()); + } } } - private void ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext context) + private void ApplyParamTags(IOpenApiParameter parameter, ParameterFilterContext context) { if (context.ParameterInfo.Member is not MethodInfo methodInfo) { @@ -81,10 +71,13 @@ private void ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext c { parameter.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml, _options?.XmlCommentEndOfLine); - var example = paramNode.GetAttribute("example"); - if (!string.IsNullOrEmpty(example)) + if (parameter is OpenApiParameter concrete) { - parameter.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, parameter.Schema, example); + var example = paramNode.GetAttribute("example"); + if (!string.IsNullOrEmpty(example)) + { + concrete.Example = XmlCommentsExampleHelper.Create(context.SchemaRepository, parameter.Schema, example); + } } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs index ea15f3e128..4eccf74285 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsRequestBodyFilter.cs @@ -1,28 +1,15 @@ using System.Reflection; using System.Xml.XPath; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; -public class XmlCommentsRequestBodyFilter : IRequestBodyFilter +public class XmlCommentsRequestBodyFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) : IRequestBodyFilter { - private readonly IReadOnlyDictionary _xmlDocMembers; - private readonly SwaggerGeneratorOptions _options; + private readonly IReadOnlyDictionary _xmlDocMembers = xmlDocMembers; + private readonly SwaggerGeneratorOptions _options = options; - public XmlCommentsRequestBodyFilter(XPathDocument xmlDoc) - : this(XmlCommentsDocumentHelper.CreateMemberDictionary(xmlDoc), null) - { - } - - [ActivatorUtilitiesConstructor] - internal XmlCommentsRequestBodyFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) - { - _xmlDocMembers = xmlDocMembers; - _options = options; - } - - public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context) + public void Apply(IOpenApiRequestBody requestBody, RequestBodyFilterContext context) { var bodyParameterDescription = context.BodyParameterDescription; @@ -70,9 +57,10 @@ public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext conte { var (summary, example) = GetParamTags(parameterFromForm); value.Description ??= summary; - if (!string.IsNullOrEmpty(example)) + + if (value is OpenApiSchema concrete && !string.IsNullOrEmpty(example)) { - value.Example ??= XmlCommentsExampleHelper.Create(context.SchemaRepository, value, example); + concrete.Example ??= XmlCommentsExampleHelper.Create(context.SchemaRepository, value, example); } } } @@ -100,7 +88,7 @@ public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext conte return (summary, exampleNode?.ToString()); } - private void ApplyPropertyTagsForBody(OpenApiRequestBody requestBody, RequestBodyFilterContext context, PropertyInfo propertyInfo) + private void ApplyPropertyTagsForBody(IOpenApiRequestBody requestBody, RequestBodyFilterContext context, PropertyInfo propertyInfo) { var (summary, example) = GetPropertyTags(propertyInfo); @@ -156,7 +144,7 @@ private void ApplyPropertyTagsForBody(OpenApiRequestBody requestBody, RequestBod return (summary, example); } - private void ApplyParamTagsForBody(OpenApiRequestBody requestBody, RequestBodyFilterContext context, ParameterInfo parameterInfo) + private void ApplyParamTagsForBody(IOpenApiRequestBody requestBody, RequestBodyFilterContext context, ParameterInfo parameterInfo) { var (summary, example) = GetParamTags(parameterInfo); diff --git a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs index b564444df5..55b334f843 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs +++ b/src/Swashbuckle.AspNetCore.SwaggerGen/XmlComments/XmlCommentsSchemaFilter.cs @@ -1,27 +1,14 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; -using System.Xml.XPath; +using System.Xml.XPath; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen; -public class XmlCommentsSchemaFilter : ISchemaFilter +public class XmlCommentsSchemaFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) : ISchemaFilter { - private readonly IReadOnlyDictionary _xmlDocMembers; - private readonly SwaggerGeneratorOptions _options; + private readonly IReadOnlyDictionary _xmlDocMembers = xmlDocMembers; + private readonly SwaggerGeneratorOptions _options = options; - public XmlCommentsSchemaFilter(XPathDocument xmlDoc) - : this(XmlCommentsDocumentHelper.CreateMemberDictionary(xmlDoc), null) - { - } - - [ActivatorUtilitiesConstructor] - internal XmlCommentsSchemaFilter(IReadOnlyDictionary xmlDocMembers, SwaggerGeneratorOptions options) - { - _xmlDocMembers = xmlDocMembers; - _options = options; - } - - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { ApplyTypeTags(schema, context.Type); @@ -31,7 +18,7 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context) } } - private void ApplyTypeTags(OpenApiSchema schema, Type type) + private void ApplyTypeTags(IOpenApiSchema schema, Type type) { var typeMemberName = XmlCommentsNodeNameHelper.GetMemberNameForType(type); @@ -45,7 +32,7 @@ private void ApplyTypeTags(OpenApiSchema schema, Type type) } } - private void ApplyMemberTags(OpenApiSchema schema, SchemaFilterContext context) + private void ApplyMemberTags(IOpenApiSchema schema, SchemaFilterContext context) { var fieldOrPropertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(context.MemberInfo); @@ -63,10 +50,13 @@ private void ApplyMemberTags(OpenApiSchema schema, SchemaFilterContext context) schema.Description = XmlCommentsTextHelper.Humanize(summaryNode, _options?.XmlCommentEndOfLine); } - var example = recordDefaultConstructorProperty.GetAttribute("example"); - if (!string.IsNullOrEmpty(example)) + if (schema is OpenApiSchema concrete) { - TrySetExample(schema, context, example); + var example = recordDefaultConstructorProperty.GetAttribute("example"); + if (!string.IsNullOrEmpty(example)) + { + TrySetExample(concrete, context, example); + } } } } @@ -79,8 +69,11 @@ private void ApplyMemberTags(OpenApiSchema schema, SchemaFilterContext context) schema.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml, _options?.XmlCommentEndOfLine); } - var exampleNode = fieldOrPropertyNode.SelectFirstChild("example"); - TrySetExample(schema, context, exampleNode?.Value); + if (schema is OpenApiSchema concrete) + { + var exampleNode = fieldOrPropertyNode.SelectFirstChild("example"); + TrySetExample(concrete, context, exampleNode?.Value); + } } } diff --git a/src/Swashbuckle.AspNetCore.SwaggerUI/Swashbuckle.AspNetCore.SwaggerUI.csproj b/src/Swashbuckle.AspNetCore.SwaggerUI/Swashbuckle.AspNetCore.SwaggerUI.csproj index e22b217a77..954e748e21 100644 --- a/src/Swashbuckle.AspNetCore.SwaggerUI/Swashbuckle.AspNetCore.SwaggerUI.csproj +++ b/src/Swashbuckle.AspNetCore.SwaggerUI/Swashbuckle.AspNetCore.SwaggerUI.csproj @@ -71,7 +71,7 @@ - <_SdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net9.0 + <_SdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net10.0 <_SdkTasksTFM Condition=" '$(MSBuildRuntimeType)' != 'Core'">net472 diff --git a/src/Swashbuckle.AspNetCore/Swashbuckle.AspNetCore.nuspec b/src/Swashbuckle.AspNetCore/Swashbuckle.AspNetCore.nuspec index 98553901cc..72de3fb9d3 100644 --- a/src/Swashbuckle.AspNetCore/Swashbuckle.AspNetCore.nuspec +++ b/src/Swashbuckle.AspNetCore/Swashbuckle.AspNetCore.nuspec @@ -25,6 +25,12 @@ + + + + + + diff --git a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsDocumentFilterTests.cs b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsDocumentFilterTests.cs index 41369ca8cf..642a3c04c8 100644 --- a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsDocumentFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsDocumentFilterTests.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.TestSupport; using Xunit; diff --git a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsOperationFilterTests.cs b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsOperationFilterTests.cs index 3478d7b284..55e6009d63 100644 --- a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsOperationFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsOperationFilterTests.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; using Xunit; @@ -20,6 +20,7 @@ public void Apply_EnrichesOperationMetadata_IfActionDecoratedWithSwaggerOperatio apiDescription: null, schemaRegistry: null, schemaRepository: null, + document: null, methodInfo: methodInfo); Subject().Apply(operation, filterContext); @@ -27,7 +28,7 @@ public void Apply_EnrichesOperationMetadata_IfActionDecoratedWithSwaggerOperatio Assert.Equal("Summary for ActionWithSwaggerOperationAttribute", operation.Summary); Assert.Equal("Description for ActionWithSwaggerOperationAttribute", operation.Description); Assert.Equal("actionWithSwaggerOperationAttribute", operation.OperationId); - Assert.Equal(["foobar"], [.. operation.Tags.Select(t => t.Name)]); + Assert.Equal(["foobar"], [.. operation.Tags.Select(t => t.Reference.Id)]); } [Fact] @@ -47,6 +48,7 @@ public void Apply_EnrichesResponseMetadata_IfActionDecoratedWithSwaggerResponseA apiDescription: null, schemaRegistry: null, schemaRepository: null, + document: null, methodInfo: methodInfo); Subject().Apply(operation, filterContext); @@ -76,6 +78,7 @@ public void Apply_EnrichesResponseMetadata_IfActionDecoratedWithSwaggerResponseC apiDescription: null, schemaRegistry: new SchemaGenerator(new SchemaGeneratorOptions(), new JsonSerializerDataContractResolver(new JsonSerializerOptions())), schemaRepository: new SchemaRepository(), + document: null, methodInfo: methodInfo); Subject().Apply(operation, filterContext); @@ -102,6 +105,7 @@ public void Apply_DelegatesToSpecifiedFilter_IfControllerDecoratedWithSwaggerOpe apiDescription: null, schemaRegistry: null, schemaRepository: null, + document: null, methodInfo: methodInfo); Subject().Apply(operation, filterContext); @@ -118,6 +122,7 @@ public void Apply_DelegatesToSpecifiedFilter_IfActionDecoratedWithSwaggerOperati apiDescription: null, schemaRegistry: null, schemaRepository: null, + document: null, methodInfo: methodInfo); Subject().Apply(operation, filterContext); @@ -152,6 +157,7 @@ public void Apply_EnrichesOperationMetadata_IfMinimalActionDecoratedWithSwaggerO apiDescription: apiDescription, schemaRegistry: null, schemaRepository: null, + document: null, methodInfo: methodInfo); Subject().Apply(operation, filterContext); @@ -159,7 +165,7 @@ public void Apply_EnrichesOperationMetadata_IfMinimalActionDecoratedWithSwaggerO Assert.Equal("Summary for ActionWithSwaggerOperationAttribute", operation.Summary); Assert.Equal("Description for ActionWithSwaggerOperationAttribute", operation.Description); Assert.Equal("actionWithSwaggerOperationAttribute", operation.OperationId); - Assert.Equal(["foobar"], [.. operation.Tags.Select(t => t.Name)]); + Assert.Equal(["foobar"], [.. operation.Tags.Select(t => t.Reference.Id)]); } private static AnnotationsOperationFilter Subject() diff --git a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsParameterFilterTests.cs b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsParameterFilterTests.cs index 6fa6a8ae4f..c722a8638e 100644 --- a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsParameterFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsParameterFilterTests.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Xunit; using Swashbuckle.AspNetCore.SwaggerGen; @@ -18,6 +18,7 @@ public void Apply_EnrichesParameterMetadata_IfParameterDecoratedWithSwaggerParam apiParameterDescription: null, schemaGenerator: null, schemaRepository: null, + document: null, parameterInfo: parameterInfo); Subject().Apply(parameter, filterContext); @@ -35,6 +36,7 @@ public void Apply_EnrichesParameterMetadata_IfPropertyDecoratedWithSwaggerParame apiParameterDescription: new ApiParameterDescription(), schemaGenerator: null, schemaRepository: null, + null, propertyInfo: propertyInfo); Subject().Apply(parameter, filterContext); @@ -54,6 +56,7 @@ public void Apply_DoesNotModifyTheRequiredFlag_IfNotSpecifiedWithSwaggerParamete apiParameterDescription: null, schemaGenerator: null, schemaRepository: null, + document: null, parameterInfo: parameterInfo); Subject().Apply(parameter, filterContext); diff --git a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsRequestBodyFilterTests.cs b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsRequestBodyFilterTests.cs index 374f380391..b258115817 100644 --- a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsRequestBodyFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsRequestBodyFilterTests.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.TestSupport; using Xunit; @@ -23,7 +23,7 @@ public void Apply_EnrichesRequestBodyMetadata_IfControllerParameterDecoratedWith { ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo } }; - var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, context); @@ -42,7 +42,7 @@ public void Apply_EnrichesRequestBodyMetadata_IfEndpointParameterDecoratedWithSw { ParameterDescriptor = new CustomParameterDescriptor { ParameterInfo = parameterInfo } }; - var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, context); @@ -58,7 +58,7 @@ public void Apply_EnrichesParameterMetadata_IfPropertyDecoratedWithSwaggerReques { ModelMetadata = ModelMetadataFactory.CreateForProperty(typeof(SwaggerAnnotatedType), nameof(SwaggerAnnotatedType.StringWithSwaggerRequestBodyAttribute)) }; - var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, context); @@ -78,7 +78,7 @@ public void Apply_DoesNotModifyTheRequiredFlag_IfNotSpecifiedWithSwaggerParamete { ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo } }; - var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var context = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, context); diff --git a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsSchemaFilterTests.cs b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsSchemaFilterTests.cs index f812a0d70f..0f8a7932db 100644 --- a/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsSchemaFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.Annotations.Test/AnnotationsSchemaFilterTests.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; using Xunit; @@ -51,7 +51,7 @@ public void Apply_EnrichesSchemaMetadata_IfPropertyDecoratedWithSwaggerSchemaAtt bool expectedWriteOnly, bool expectedNullable) { - var schema = new OpenApiSchema { Nullable = true }; + var schema = new OpenApiSchema { Type = JsonSchemaType.Null }; var propertyInfo = declaringType .GetProperty(propertyName); var context = new SchemaFilterContext( @@ -66,13 +66,13 @@ public void Apply_EnrichesSchemaMetadata_IfPropertyDecoratedWithSwaggerSchemaAtt Assert.Equal("date", schema.Format); Assert.Equal(expectedReadOnly, schema.ReadOnly); Assert.Equal(expectedWriteOnly, schema.WriteOnly); - Assert.Equal(expectedNullable, schema.Nullable); + Assert.Equal(expectedNullable, schema.Type.Value.HasFlag(JsonSchemaType.Null)); } [Fact] public void Apply_DoesNotModifyFlags_IfNotSpecifiedWithSwaggerSchemaAttribute() { - var schema = new OpenApiSchema { ReadOnly = true, WriteOnly = true, Nullable = true }; + var schema = new OpenApiSchema { ReadOnly = true, WriteOnly = true, Type = JsonSchemaType.Null }; var propertyInfo = typeof(SwaggerAnnotatedType) .GetProperty(nameof(SwaggerAnnotatedType.StringWithSwaggerSchemaAttributeDescriptionOnly)); var context = new SchemaFilterContext( @@ -85,7 +85,7 @@ public void Apply_DoesNotModifyFlags_IfNotSpecifiedWithSwaggerSchemaAttribute() Assert.True(schema.ReadOnly); Assert.True(schema.WriteOnly); - Assert.True(schema.Nullable); + Assert.True(schema.Type.Value.HasFlag(JsonSchemaType.Null)); } [Theory] diff --git a/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsOperationFilter.cs b/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsOperationFilter.cs index 245281c4f4..d6dc05005c 100644 --- a/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsOperationFilter.cs +++ b/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsOperationFilter.cs @@ -1,5 +1,4 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Annotations.Test; @@ -8,6 +7,7 @@ public class VendorExtensionsOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { - operation.Extensions.Add("X-property1", new OpenApiString("value")); + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add("X-property1", new JsonNodeExtension("value")); } } diff --git a/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsSchemaFilter.cs b/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsSchemaFilter.cs index 778e553035..492fe9d4db 100644 --- a/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsSchemaFilter.cs +++ b/test/Swashbuckle.AspNetCore.Annotations.Test/Fixtures/VendorExtensionsSchemaFilter.cs @@ -1,13 +1,16 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Annotations.Test; public class VendorExtensionsSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { - schema.Extensions.Add("X-property1", new OpenApiString("value")); + if (schema is OpenApiSchema openApiSchema) + { + openApiSchema.Extensions ??= new Dictionary(); + openApiSchema.Extensions.Add("X-property1", new JsonNodeExtension("value")); + } } } diff --git a/test/Swashbuckle.AspNetCore.ApiTesting.Test/ApiTestRunnerBaseTests.cs b/test/Swashbuckle.AspNetCore.ApiTesting.Test/ApiTestRunnerBaseTests.cs index 85c3a812d5..288883144b 100644 --- a/test/Swashbuckle.AspNetCore.ApiTesting.Test/ApiTestRunnerBaseTests.cs +++ b/test/Swashbuckle.AspNetCore.ApiTesting.Test/ApiTestRunnerBaseTests.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Xunit; namespace Swashbuckle.AspNetCore.ApiTesting.Test; @@ -54,9 +54,9 @@ public async Task TestAsync_ThrowsException_IfExpectedStatusCodeIs2xxAndRequestD { ["/api/products"] = new OpenApiPathItem { - Operations = new Dictionary + Operations = new Dictionary { - [OperationType.Get] = new OpenApiOperation + [HttpMethod.Get] = new OpenApiOperation { OperationId = "GetProducts", Parameters = @@ -110,9 +110,9 @@ public async Task TestAsync_ThrowsException_IfResponseDoesNotMatchSpec( { ["/api/products"] = new OpenApiPathItem { - Operations = new Dictionary + Operations = new Dictionary { - [OperationType.Get] = new OpenApiOperation + [HttpMethod.Get] = new OpenApiOperation { OperationId = "GetProducts", Responses = new OpenApiResponses diff --git a/test/Swashbuckle.AspNetCore.ApiTesting.Test/JsonValidatorTests.cs b/test/Swashbuckle.AspNetCore.ApiTesting.Test/JsonValidatorTests.cs index 2eed054370..9f78ec43fb 100644 --- a/test/Swashbuckle.AspNetCore.ApiTesting.Test/JsonValidatorTests.cs +++ b/test/Swashbuckle.AspNetCore.ApiTesting.Test/JsonValidatorTests.cs @@ -1,9 +1,8 @@ -using Microsoft.OpenApi.Models; +using System.Globalization; +using Microsoft.OpenApi; using Newtonsoft.Json.Linq; using Xunit; -using JsonSchemaType = string; - namespace Swashbuckle.AspNetCore.ApiTesting.Test; public class JsonValidatorTests @@ -77,7 +76,7 @@ public void Validate_ReturnsError_IfNumberGreaterThanMaximum( bool expectedReturnValue, string expectedErrorMessage) { - var openApiSchema = new OpenApiSchema { Type = JsonSchemaTypes.Number, Maximum = schemaMaximum }; + var openApiSchema = new OpenApiSchema { Type = JsonSchemaTypes.Number, Maximum = schemaMaximum.ToString(CultureInfo.InvariantCulture) }; var instance = JToken.Parse(instanceText); var returnValue = Subject().Validate( @@ -102,8 +101,8 @@ public void Validate_ReturnsError_IfNumberGreaterThanOrEqualToMaximumAndExclusiv var openApiSchema = new OpenApiSchema { Type = JsonSchemaTypes.Number, - Maximum = schemaMaximum, - ExclusiveMaximum = true + Maximum = schemaMaximum.ToString(CultureInfo.InvariantCulture), + ExclusiveMaximum = schemaMaximum.ToString(CultureInfo.InvariantCulture), }; var instance = JToken.Parse(instanceText); @@ -126,7 +125,7 @@ public void Validate_ReturnsError_IfNumberLessThanMinimum( bool expectedReturnValue, string expectedErrorMessage) { - var openApiSchema = new OpenApiSchema { Type = JsonSchemaTypes.Number, Minimum = schemaMinimum }; + var openApiSchema = new OpenApiSchema { Type = JsonSchemaTypes.Number, Minimum = schemaMinimum.ToString(CultureInfo.InvariantCulture) }; var instance = JToken.Parse(instanceText); var returnValue = Subject().Validate( @@ -151,8 +150,8 @@ public void Validate_ReturnsError_IfNumberLessThanOrEqualToMinimumAndExclusiveMi var openApiSchema = new OpenApiSchema { Type = JsonSchemaTypes.Number, - Minimum = schemaMinimum, - ExclusiveMinimum = true + Minimum = schemaMinimum.ToString(CultureInfo.InvariantCulture), + ExclusiveMinimum = schemaMinimum.ToString(CultureInfo.InvariantCulture), }; var instance = JToken.Parse(instanceText); @@ -451,7 +450,7 @@ public void Validate_ReturnsError_IfKnownPropertyDoesNotMatchPropertySchema( var openApiSchema = new OpenApiSchema { Type = JsonSchemaTypes.Object, - Properties = new Dictionary + Properties = new Dictionary { ["id"] = new OpenApiSchema { Type = propertySchemaType } } @@ -622,15 +621,12 @@ public void Validate_SupportsReferencedSchemas_IfDefinedInProvidedOpenApiDocumen string referenceId, string expectedExceptionMessage) { - var openApiSchema = new OpenApiSchema - { - Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = referenceId } - }; + var openApiSchema = new OpenApiSchemaReference(referenceId); var openApiDocument = new OpenApiDocument { Components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { ["ref"] = new OpenApiSchema { Type = JsonSchemaTypes.Number } } diff --git a/test/Swashbuckle.AspNetCore.ApiTesting.Test/RequestValidatorTests.cs b/test/Swashbuckle.AspNetCore.ApiTesting.Test/RequestValidatorTests.cs index dc0bc1d1ae..ccc498e114 100644 --- a/test/Swashbuckle.AspNetCore.ApiTesting.Test/RequestValidatorTests.cs +++ b/test/Swashbuckle.AspNetCore.ApiTesting.Test/RequestValidatorTests.cs @@ -1,9 +1,7 @@ using System.Text; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Xunit; -using JsonSchemaType = string; - namespace Swashbuckle.AspNetCore.ApiTesting.Test; public class RequestValidatorTests @@ -16,7 +14,7 @@ public void Validate_ThrowsException_IfUriDoesNotMatchPathTemplate( string pathTemplate, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation(pathTemplate, OperationType.Get, new OpenApiOperation()); + var openApiDocument = DocumentWithOperation(pathTemplate, HttpMethod.Get, new OpenApiOperation()); var request = new HttpRequestMessage { RequestUri = new Uri(uriString, UriKind.Relative), @@ -24,21 +22,21 @@ public void Validate_ThrowsException_IfUriDoesNotMatchPathTemplate( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, pathTemplate, OperationType.Get); + Subject().Validate(request, openApiDocument, pathTemplate, HttpMethod.Get); }); Assert.Equal(expectedErrorMessage, exception?.Message); } [Theory] - [InlineData("POST", OperationType.Get, "Request method 'POST' does not match specified operation type 'Get'")] - [InlineData("GET", OperationType.Get, null)] + [InlineData("POST", "GET", "Request method 'POST' does not match specified operation type 'GET'")] + [InlineData("GET", "GET", null)] public void Validate_ThrowsException_IfMethodDoesNotMatchOperationType( string methodString, - OperationType operationType, + string operationType, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", operationType, new OpenApiOperation()); + var openApiDocument = DocumentWithOperation("/api/products", new(operationType), new OpenApiOperation()); var request = new HttpRequestMessage { RequestUri = new Uri("/api/products", UriKind.Relative), @@ -47,7 +45,7 @@ public void Validate_ThrowsException_IfMethodDoesNotMatchOperationType( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products", operationType); + Subject().Validate(request, openApiDocument, "/api/products", new(operationType)); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -60,7 +58,7 @@ public void Validate_ThrowsException_IfRequiredQueryParameterIsNotPresent( string uriString, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Get, new OpenApiOperation { Parameters = [ @@ -81,7 +79,7 @@ public void Validate_ThrowsException_IfRequiredQueryParameterIsNotPresent( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products", OperationType.Get); + Subject().Validate(request, openApiDocument, "/api/products", HttpMethod.Get); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -94,7 +92,7 @@ public void Validate_ThrowsException_IfRequiredHeaderParameterIsNotPresent( string parameterValue, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Get, new OpenApiOperation { Parameters = [ @@ -116,7 +114,7 @@ public void Validate_ThrowsException_IfRequiredHeaderParameterIsNotPresent( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products", OperationType.Get); + Subject().Validate(request, openApiDocument, "/api/products", HttpMethod.Get); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -138,7 +136,7 @@ public void Validate_ThrowsException_IfPathParameterIsNotOfSpecifiedType( JsonSchemaType specifiedType, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products/{param}", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products/{param}", HttpMethod.Get, new OpenApiOperation { Parameters = [ @@ -158,7 +156,7 @@ public void Validate_ThrowsException_IfPathParameterIsNotOfSpecifiedType( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products/{param}", OperationType.Get); + Subject().Validate(request, openApiDocument, "/api/products/{param}", HttpMethod.Get); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -173,7 +171,7 @@ public void Validate_ThrowsException_IfPathParameterIsNotOfSpecifiedType( { "/api/products?param=1", JsonSchemaTypes.Number, null, null }, { "/api/products?param=foo", JsonSchemaTypes.String, null, null }, { "/api/products?param=1¶m=2", JsonSchemaTypes.Array, JsonSchemaTypes.Number, null }, - { "/api/products?param=1¶m=foo", JsonSchemaTypes.Array, JsonSchemaTypes.Number, "Parameter 'param' is not of type 'array[number]'" }, + { "/api/products?param=1¶m=foo", JsonSchemaTypes.Array, JsonSchemaTypes.Number, "Parameter 'param' is not of type 'array[Number]'" }, }; [Theory] @@ -184,7 +182,7 @@ public void Validate_ThrowsException_IfQueryParameterIsNotOfSpecifiedType( JsonSchemaType? specifiedItemsType, string? expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Get, new OpenApiOperation { Parameters = [ @@ -208,7 +206,7 @@ public void Validate_ThrowsException_IfQueryParameterIsNotOfSpecifiedType( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products", OperationType.Get); + Subject().Validate(request, openApiDocument, "/api/products", HttpMethod.Get); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -222,7 +220,7 @@ public void Validate_ThrowsException_IfQueryParameterIsNotOfSpecifiedType( { "1", JsonSchemaTypes.Number, null, null }, { "foo", JsonSchemaTypes.String, null, null }, { "1,2", JsonSchemaTypes.Array, JsonSchemaTypes.Number, null }, - { "1,foo", JsonSchemaTypes.Array, JsonSchemaTypes.Number, "Parameter 'test-header' is not of type 'array[number]'" }, + { "1,foo", JsonSchemaTypes.Array, JsonSchemaTypes.Number, "Parameter 'test-header' is not of type 'array[Number]'" }, }; [Theory] @@ -233,7 +231,7 @@ public void Validate_ThrowsException_IfHeaderParameterIsNotOfSpecifiedType( JsonSchemaType? specifiedItemsType, string? expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Get, new OpenApiOperation { Parameters = [ @@ -258,7 +256,7 @@ public void Validate_ThrowsException_IfHeaderParameterIsNotOfSpecifiedType( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products", OperationType.Get); + Subject().Validate(request, openApiDocument, "/api/products", HttpMethod.Get); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -272,7 +270,7 @@ public void Validate_ThrowsException_IfRequiredContentIsNotPresent( string contentString, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Post, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Post, new OpenApiOperation { RequestBody = new OpenApiRequestBody { @@ -292,7 +290,7 @@ public void Validate_ThrowsException_IfRequiredContentIsNotPresent( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products", OperationType.Post); + Subject().Validate(request, openApiDocument, "/api/products", HttpMethod.Post); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -305,7 +303,7 @@ public void Validate_ThrowsException_IfContentMediaTypeIsNotSpecified( string mediaType, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Post, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Post, new OpenApiOperation { RequestBody = new OpenApiRequestBody { @@ -324,7 +322,7 @@ public void Validate_ThrowsException_IfContentMediaTypeIsNotSpecified( var exception = Record.Exception(() => { - Subject().Validate(request, openApiDocument, "/api/products", OperationType.Post); + Subject().Validate(request, openApiDocument, "/api/products", HttpMethod.Post); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -337,7 +335,7 @@ public void Validate_DelegatesContentValidationToInjectedContentValidators( string jsonString, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Post, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Post, new OpenApiOperation { RequestBody = new OpenApiRequestBody { @@ -363,13 +361,13 @@ public void Validate_DelegatesContentValidationToInjectedContentValidators( var exception = Record.Exception(() => { - Subject([new JsonContentValidator()]).Validate(request, openApiDocument, "/api/products", OperationType.Post); + Subject([new JsonContentValidator()]).Validate(request, openApiDocument, "/api/products", HttpMethod.Post); }); Assert.Equal(expectedErrorMessage, exception?.Message); } - private static OpenApiDocument DocumentWithOperation(string pathTemplate, OperationType operationType, OpenApiOperation operationSpec) + private static OpenApiDocument DocumentWithOperation(string pathTemplate, HttpMethod operationType, OpenApiOperation operationSpec) { return new OpenApiDocument { @@ -377,7 +375,7 @@ private static OpenApiDocument DocumentWithOperation(string pathTemplate, Operat { [pathTemplate] = new OpenApiPathItem { - Operations = new Dictionary + Operations = new Dictionary { [operationType] = operationSpec } @@ -385,7 +383,7 @@ private static OpenApiDocument DocumentWithOperation(string pathTemplate, Operat }, Components = new OpenApiComponents { - Schemas = new Dictionary() + Schemas = new Dictionary(), } }; } diff --git a/test/Swashbuckle.AspNetCore.ApiTesting.Test/ResponseValidatorTests.cs b/test/Swashbuckle.AspNetCore.ApiTesting.Test/ResponseValidatorTests.cs index bb5eafe01e..1c4c31db8e 100644 --- a/test/Swashbuckle.AspNetCore.ApiTesting.Test/ResponseValidatorTests.cs +++ b/test/Swashbuckle.AspNetCore.ApiTesting.Test/ResponseValidatorTests.cs @@ -1,10 +1,8 @@ using System.Net; using System.Text; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Xunit; -using JsonSchemaType = string; - namespace Swashbuckle.AspNetCore.ApiTesting.Test; public class ResponseValidatorTests @@ -16,7 +14,7 @@ public void Validate_ThrowsException_IfStatusCodeDifferentToExpectedResponseCode HttpStatusCode statusCode, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Get, new OpenApiOperation { Responses = new OpenApiResponses { @@ -31,7 +29,7 @@ public void Validate_ThrowsException_IfStatusCodeDifferentToExpectedResponseCode var exception = Record.Exception(() => { - Subject().Validate(response, openApiDocument, "/api/products", OperationType.Get, "200"); + Subject().Validate(response, openApiDocument, "/api/products", HttpMethod.Get, "200"); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -44,13 +42,13 @@ public void Validate_ThrowsException_IfRequiredHeaderIsNotPresent( string headerValue, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Post, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Post, new OpenApiOperation { Responses = new OpenApiResponses { ["201"] = new OpenApiResponse { - Headers = new Dictionary + Headers = new Dictionary { ["test-header"] = new OpenApiHeader { @@ -68,7 +66,7 @@ public void Validate_ThrowsException_IfRequiredHeaderIsNotPresent( var exception = Record.Exception(() => { - Subject().Validate(response, openApiDocument, "/api/products", OperationType.Post, "201"); + Subject().Validate(response, openApiDocument, "/api/products", HttpMethod.Post, "201"); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -83,7 +81,7 @@ public void Validate_ThrowsException_IfRequiredHeaderIsNotPresent( { "1", JsonSchemaTypes.Number, null, null }, { "foo", JsonSchemaTypes.String, null, null }, { "1,2", JsonSchemaTypes.Array, JsonSchemaTypes.Number, null }, - { "1,foo", JsonSchemaTypes.Array, JsonSchemaTypes.Number, "Header 'test-header' is not of type 'array[number]'" }, + { "1,foo", JsonSchemaTypes.Array, JsonSchemaTypes.Number, "Header 'test-header' is not of type 'array[Number]'" }, }; [Theory] @@ -94,13 +92,13 @@ public void Validate_ThrowsException_IfHeaderIsNotOfSpecifiedType( JsonSchemaType? specifiedItemsType, string? expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products", OperationType.Post, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products", HttpMethod.Post, new OpenApiOperation { Responses = new OpenApiResponses { ["201"] = new OpenApiResponse { - Headers = new Dictionary + Headers = new Dictionary { ["test-header"] = new OpenApiHeader { @@ -122,7 +120,7 @@ public void Validate_ThrowsException_IfHeaderIsNotOfSpecifiedType( var exception = Record.Exception(() => { - Subject().Validate(response, openApiDocument, "/api/products", OperationType.Post, "201"); + Subject().Validate(response, openApiDocument, "/api/products", HttpMethod.Post, "201"); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -136,7 +134,7 @@ public void Validate_ThrowsException_IfExpectedContentIsNotPresent( string contentString, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products/1", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products/1", HttpMethod.Get, new OpenApiOperation { Responses = new OpenApiResponses { @@ -156,7 +154,7 @@ public void Validate_ThrowsException_IfExpectedContentIsNotPresent( var exception = Record.Exception(() => { - Subject().Validate(response, openApiDocument, "/api/products/1", OperationType.Get, "200"); + Subject().Validate(response, openApiDocument, "/api/products/1", HttpMethod.Get, "200"); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -169,7 +167,7 @@ public void Validate_ThrowsException_IfContentMediaTypeIsNotSpecified( string mediaType, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products/1", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products/1", HttpMethod.Get, new OpenApiOperation { Responses = new OpenApiResponses { @@ -189,7 +187,7 @@ public void Validate_ThrowsException_IfContentMediaTypeIsNotSpecified( var exception = Record.Exception(() => { - Subject().Validate(response, openApiDocument, "/api/products/1", OperationType.Get, "200"); + Subject().Validate(response, openApiDocument, "/api/products/1", HttpMethod.Get, "200"); }); Assert.Equal(expectedErrorMessage, exception?.Message); @@ -202,7 +200,7 @@ public void Validate_DelegatesContentValidationToInjectedContentValidators( string jsonString, string expectedErrorMessage) { - var openApiDocument = DocumentWithOperation("/api/products/1", OperationType.Get, new OpenApiOperation + var openApiDocument = DocumentWithOperation("/api/products/1", HttpMethod.Get, new OpenApiOperation { Responses = new OpenApiResponses { @@ -229,14 +227,14 @@ public void Validate_DelegatesContentValidationToInjectedContentValidators( var exception = Record.Exception(() => { - Subject([new JsonContentValidator()]).Validate(response, openApiDocument, "/api/products/1", OperationType.Get, "200"); + Subject([new JsonContentValidator()]).Validate(response, openApiDocument, "/api/products/1", HttpMethod.Get, "200"); }); Assert.Equal(expectedErrorMessage, exception?.Message); } - private static OpenApiDocument DocumentWithOperation(string pathTemplate, OperationType operationType, OpenApiOperation operationSpec) + private static OpenApiDocument DocumentWithOperation(string pathTemplate, HttpMethod operationType, OpenApiOperation operationSpec) { return new OpenApiDocument { @@ -244,7 +242,7 @@ private static OpenApiDocument DocumentWithOperation(string pathTemplate, Operat { [pathTemplate] = new OpenApiPathItem { - Operations = new Dictionary + Operations = new Dictionary { [operationType] = operationSpec } @@ -252,7 +250,7 @@ private static OpenApiDocument DocumentWithOperation(string pathTemplate, Operat }, Components = new OpenApiComponents { - Schemas = new Dictionary() + Schemas = new Dictionary(), } }; } diff --git a/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs b/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs index a57cb33235..facefaddc3 100644 --- a/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs +++ b/test/Swashbuckle.AspNetCore.Cli.Test/ToolTests.cs @@ -89,6 +89,28 @@ public static void Can_Generate_Swagger_Json_v3() Assert.True(productsPath.TryGetProperty("post", out _)); } + [Fact] + public static void Can_Generate_Swagger_Json_v3_1() + { + using var document = RunToJsonCommand((outputPath) => + [ + "tofile", + "--output", + outputPath, + "--openapiversion", + "3.1", + Path.Combine(Directory.GetCurrentDirectory(), "Basic.dll"), + "v1" + ]); + + Assert.StartsWith("3.1.", document.RootElement.GetProperty("openapi").GetString()); + + // verify one of the endpoints + var paths = document.RootElement.GetProperty("paths"); + var productsPath = paths.GetProperty("/products"); + Assert.True(productsPath.TryGetProperty("post", out _)); + } + [Fact] public static void Can_Generate_Swagger_Json_v3_OpenApiVersion() { @@ -173,6 +195,26 @@ public static void CustomDocumentSerializer_Writes_Custom_V3_Document() Assert.Equal("DocumentSerializerTest3.0", swaggerInfo); } + [Fact] + public static void CustomDocumentSerializer_Writes_Custom_V3_1_Document() + { + using var document = RunToJsonCommand((outputPath) => + [ + "tofile", + "--output", + outputPath, + "--openapiversion", + "3.1", + Path.Combine(Directory.GetCurrentDirectory(), + "CustomDocumentSerializer.dll"), + "v1" + ]); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest3.1", swaggerInfo); + } + [Fact] public static void Can_Generate_Swagger_Json_ForTopLevelApp() { diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs index cdf8f9c6b4..e6d674972b 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/CustomDocumentSerializerTests.cs @@ -10,6 +10,23 @@ namespace Swashbuckle.AspNetCore.IntegrationTests; [Collection("TestSite")] public class CustomDocumentSerializerTests(ITestOutputHelper outputHelper) { + [Fact] + public async Task TestSite_Writes_Custom_V3_1_Document() + { + var testSite = new TestSite(typeof(CustomDocumentSerializer.Startup), outputHelper); + var client = testSite.BuildClient(); + + var swaggerResponse = await client.GetAsync($"/swagger/v1/swaggerv3_1.json", TestContext.Current.CancellationToken); + + swaggerResponse.EnsureSuccessStatusCode(); + var contentStream = await swaggerResponse.Content.ReadAsStreamAsync(TestContext.Current.CancellationToken); + using var document = JsonDocument.Parse(contentStream); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest3.1", swaggerInfo); + } + [Fact] public async Task TestSite_Writes_Custom_V3_Document() { @@ -69,6 +86,34 @@ public async Task DocumentProvider_Writes_Custom_V3_Document() Assert.Equal("DocumentSerializerTest3.0", swaggerInfo); } + [Fact] + public async Task DocumentProvider_Writes_Custom_V3_1_Document() + { + var testSite = new TestSite(typeof(CustomDocumentSerializer.Startup), outputHelper); + var server = testSite.BuildServer(); + var services = server.Services; + + var documentProvider = services.GetService(); + var options = services.GetService>(); + options.Value.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_1; + + using var stream = new MemoryStream(); + + using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 2048, leaveOpen: true)) + { + await documentProvider.GenerateAsync("v1", writer); + await writer.FlushAsync(TestContext.Current.CancellationToken); + } + + stream.Position = 0L; + + using var document = JsonDocument.Parse(stream); + + // verify that the custom serializer wrote the swagger info + var swaggerInfo = document.RootElement.GetProperty("swagger").GetString(); + Assert.Equal("DocumentSerializerTest3.1", swaggerInfo); + } + [Fact] public async Task DocumentProvider_Writes_Custom_V2_Document() { diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/HttpServerFixture.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/HttpServerFixture.cs new file mode 100644 index 0000000000..a752427cd4 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/HttpServerFixture.cs @@ -0,0 +1,20 @@ +#if NET10_0_OR_GREATER +using Microsoft.AspNetCore.Mvc.Testing; + +namespace Swashbuckle.AspNetCore.IntegrationTests; + +public class HttpApplicationFixture : WebApplicationFactory + where TEntryPoint : class +{ + public HttpApplicationFixture() => UseKestrel(0); + + public string ServerUrl + { + get + { + StartServer(); + return ClientOptions.BaseAddress.ToString(); + } + } +} +#endif diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/OpenApiDocumentLoader.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/OpenApiDocumentLoader.cs index 07ec16d375..cdcd53554a 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/OpenApiDocumentLoader.cs +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/OpenApiDocumentLoader.cs @@ -1,5 +1,5 @@ -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Readers; +using Microsoft.OpenApi; +using Microsoft.OpenApi.Reader; namespace Swashbuckle.AspNetCore; @@ -7,15 +7,23 @@ internal static class OpenApiDocumentLoader { public static async Task LoadAsync(Stream stream) { - var reader = new OpenApiStreamReader(); - var document = reader.Read(stream, out OpenApiDiagnostic diagnostic); - return await Task.FromResult(document); + var result = await OpenApiDocument.LoadAsync(stream); + + Assert.NotNull(result); + Assert.NotNull(result.Document); + Assert.NotNull(result.Diagnostic); + Assert.Empty(result.Diagnostic.Errors); + Assert.Empty(result.Diagnostic.Warnings); + + return result.Document; } public static async Task<(OpenApiDocument Document, OpenApiDiagnostic Diagnostic)> LoadWithDiagnosticsAsync(Stream stream) { - var reader = new OpenApiStreamReader(); - var document = reader.Read(stream, out OpenApiDiagnostic diagnostic); - return await Task.FromResult((document, diagnostic)); + var settings = new OpenApiReaderSettings(); + settings.AddYamlReader(); + + var result = await OpenApiDocument.LoadAsync(stream, settings: settings); + return (result.Document, result.Diagnostic); } } diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/PlaywrightFixture.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/PlaywrightFixture.cs new file mode 100644 index 0000000000..f0e4764fb5 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/PlaywrightFixture.cs @@ -0,0 +1,65 @@ +#if NET10_0_OR_GREATER +using Microsoft.Playwright; + +namespace Swashbuckle.AspNetCore.IntegrationTests; + +public sealed class PlaywrightFixture : IAsyncLifetime +{ + private bool _installed; + + public ValueTask InitializeAsync() + { + EnsureInstalled(); + return ValueTask.CompletedTask; + } + + public ValueTask DisposeAsync() + { + GC.SuppressFinalize(this); + return ValueTask.CompletedTask; + } + + public async Task VerifyPage(string url, Func test) + { + EnsureInstalled(); + + using var playwright = await Playwright.CreateAsync(); + var browserType = playwright[BrowserType.Chromium]; + + var options = new BrowserTypeLaunchOptions(); + + if (System.Diagnostics.Debugger.IsAttached) + { +#pragma warning disable CS0612 + options.Devtools = true; +#pragma warning restore CS0612 + options.Headless = false; + options.SlowMo = 100; + } + + await using var browser = await playwright[BrowserType.Chromium].LaunchAsync(options); + await using var context = await browser.NewContextAsync(); + + var page = await context.NewPageAsync(); + + await page.GotoAsync(url, new() { WaitUntil = WaitUntilState.NetworkIdle }); + + await test(page); + } + + private void EnsureInstalled() + { + if (!_installed) + { + int result = Microsoft.Playwright.Program.Main(["install", "chromium", "--only-shell", "--with-deps"]); + + if (result != 0) + { + throw new InvalidOperationException($"Failed to install Playwright dependencies: {result}."); + } + + _installed = true; + } + } +} +#endif diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerIntegrationTests.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerIntegrationTests.cs index 55ee5c5f94..c798078c97 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerIntegrationTests.cs +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerIntegrationTests.cs @@ -2,7 +2,6 @@ using System.Reflection; using System.Text; using System.Text.Json; -using Microsoft.OpenApi.Any; using ReDocApp = ReDoc; namespace Swashbuckle.AspNetCore.IntegrationTests; @@ -85,8 +84,7 @@ public async Task SwaggerEndpoint_ReturnsCorrectPriceExample_ForDifferentCulture { var openApiDocument = await OpenApiDocumentLoader.LoadAsync(contentStream); var example = openApiDocument.Components.Schemas["Product"].Example; - var exampleObject = Assert.IsType(example); - double price = Assert.IsType(exampleObject["price"]).Value; + double price = example["price"].GetValue(); Assert.Equal(14.37, price); } finally @@ -98,6 +96,7 @@ public async Task SwaggerEndpoint_ReturnsCorrectPriceExample_ForDifferentCulture [Theory] [InlineData("/swagger/v1/swagger.json", "openapi", "3.0.4")] [InlineData("/swagger/v1/swaggerv2.json", "swagger", "2.0")] + [InlineData("/swagger/v1/swaggerv3_1.json", "openapi", "3.1.1")] public async Task SwaggerMiddleware_CanBeConfiguredMultipleTimes( string swaggerUrl, string expectedVersionProperty, diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj b/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj index 3d3a84a83e..3cc0923207 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/Swashbuckle.AspNetCore.IntegrationTests.csproj @@ -18,7 +18,8 @@ - + + @@ -30,13 +31,18 @@ - - + + - - + + + + + + + diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/UITests.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/UITests.cs new file mode 100644 index 0000000000..fc5293784b --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/UITests.cs @@ -0,0 +1,48 @@ +#if NET10_0_OR_GREATER +using ReDocApp = ReDoc; + +namespace Swashbuckle.AspNetCore.IntegrationTests; + +public class UITests(PlaywrightFixture fixture) : IClassFixture +{ + [Fact] + public async Task Can_Load_SwaggerUI_Page_And_Make_Request() + { + // Arrange + await using var application = new SwaggerUIFixture(); + + // Act and Assert + await fixture.VerifyPage(application.ServerUrl, async (page) => + { + var operation = await page.WaitForSelectorAsync("text=Searches the collection of products by description key words"); + await operation.ClickAsync(); + + var button = await page.WaitForSelectorAsync("text=Try it out"); + await button.ClickAsync(); + + button = await page.WaitForSelectorAsync("text=Execute"); + await button.ClickAsync(); + + var response = await page.WaitForSelectorAsync(".live-responses-table"); + await response.WaitForSelectorAsync("text=200"); + }); + } + + [Fact] + public async Task Can_Load_Redoc_Page() + { + // Arrange + await using var application = new RedocFixture(); + + // Act and Assert + await fixture.VerifyPage(application.ServerUrl, async (page) => + { + await page.QuerySelectorAsync("text=/products"); + }); + } + + private sealed class RedocFixture : HttpApplicationFixture; + + private sealed class SwaggerUIFixture : HttpApplicationFixture; +} +#endif diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet10_0.verified.txt new file mode 100644 index 0000000000..f0b5be055c --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet10_0.verified.txt @@ -0,0 +1,59 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "CliExampleWithFactory", + "version": "1.0" + }, + "servers": [ + { + "url": "http://localhost:57556/" + } + ], + "paths": { + "/products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet8_0.verified.txt index 13e135e2cf..f0b5be055c 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet8_0.verified.txt @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet9_0.verified.txt index 13e135e2cf..f0b5be055c 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_ForAutofaq.DotNet9_0.verified.txt @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..97a6f4f1bb --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,1718 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API V1", + "description": "A sample API for testing Swashbuckle", + "termsOfService": "http://tempuri.org/terms", + "version": "v1" + }, + "paths": { + "/products": { + "post": { + "tags": [ + "CrudActions" + ], + "summary": "Creates a product", + "description": "## Heading 1\r\n\r\n POST /products\r\n {\r\n \"id\": \"123\",\r\n \"description\": \"Some product\"\r\n }", + "operationId": "CreateProduct", + "requestBody": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + }, + "required": true, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + }, + "x-purpose": "test" + }, + "get": { + "tags": [ + "CrudActions" + ], + "summary": "Searches the collection of products by description key words", + "operationId": "SearchProducts", + "parameters": [ + { + "name": "kw", + "in": "query", + "description": "A list of search terms", + "schema": { + "type": "string", + "default": "foobar" + }, + "example": "hello" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/products/all": { + "get": { + "tags": [ + "CrudActions" + ], + "summary": "Get all products", + "description": "```\r\n{\r\n \"Id\":1,\r\n \"Description\":\"\",\r\n \"Status\": 0,\r\n \"Status2\": 1\r\n}\r\n \r\n```", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/products/{id}": { + "get": { + "tags": [ + "CrudActions" + ], + "summary": "Returns a specific product", + "operationId": "GetProduct", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The product id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 111 + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + }, + "x-purpose": "test" + }, + "put": { + "tags": [ + "CrudActions" + ], + "summary": "Updates all properties of a specific product", + "operationId": "UpdateProduct", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 222 + } + ], + "requestBody": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + }, + "required": true, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + }, + "patch": { + "tags": [ + "CrudActions" + ], + "summary": "Updates some properties of a specific product", + "description": "\r\nOnly provided properties will be updated,\r\n other remain unchanged.\r\n\r\nIdentifier must be non-default value\r\n\r\nBody must be specified", + "operationId": "PatchProduct", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 333 + } + ], + "requestBody": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { } + } + }, + "text/json": { + "schema": { + "type": "object", + "additionalProperties": { } + } + }, + "application/*+json": { + "schema": { + "type": "object", + "additionalProperties": { } + } + } + }, + "required": true, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + }, + "delete": { + "tags": [ + "CrudActions" + ], + "summary": "Deletes a specific product", + "operationId": "DeleteProduct", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 444 + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/payments/authorize": { + "post": { + "tags": [ + "DataAnnotations" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PaymentRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/PaymentRequest" + } + } + }, + "required": true, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/payments/{paymentId}/cancel": { + "put": { + "tags": [ + "DataAnnotations" + ], + "parameters": [ + { + "name": "paymentId", + "in": "path", + "required": true, + "schema": { + "minLength": 6, + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/kittens": { + "post": { + "tags": [ + "DynamicTypes" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { } + }, + "text/json": { + "schema": { } + }, + "application/*+json": { + "schema": { } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/unicorns": { + "get": { + "tags": [ + "DynamicTypes" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { } + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/dragons": { + "post": { + "tags": [ + "DynamicTypes" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { } + }, + "text/json": { + "schema": { } + }, + "application/*+json": { + "schema": { } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/files/single": { + "post": { + "tags": [ + "Files" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + }, + "encoding": { + "file": { + "style": "form" + } + } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/files/multiple": { + "post": { + "tags": [ + "Files" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "files": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + } + } + }, + "encoding": { + "files": { + "style": "form" + } + } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/files/form-with-file": { + "post": { + "tags": [ + "Files" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "file": { + "type": "string", + "format": "binary" + } + } + }, + "encoding": { + "name": { + "style": "form" + }, + "file": { + "style": "form" + } + } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/files/{name}": { + "get": { + "tags": [ + "Files" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "oneOf": [ + { + "type": "string", + "format": "binary" + }, + { + "type": "string", + "format": "binary" + }, + { + "type": "string", + "format": "binary" + }, + { + "type": "string", + "format": "binary" + } + ] + } + }, + "application/zip": { + "schema": { + "oneOf": [ + { + "type": "string", + "format": "binary" + }, + { + "type": "string", + "format": "binary" + }, + { + "type": "string", + "format": "binary" + }, + { + "type": "string", + "format": "binary" + } + ] + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/registrations": { + "post": { + "tags": [ + "FromFormParams" + ], + "summary": "Form parameters with description", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Summary for Name", + "example": "MyName" + }, + "phoneNumbers": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Summary for PhoneNumbers" + }, + "formFile": { + "type": "string", + "description": "Description for file", + "format": "binary" + }, + "text": { + "type": "string", + "description": "Description for Text" + } + } + }, + "encoding": { + "name": { + "style": "form" + }, + "phoneNumbers": { + "style": "form" + }, + "formFile": { + "style": "form" + }, + "text": { + "style": "form" + } + } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/registrationsWithIgnoreProperties": { + "post": { + "tags": [ + "FromFormParams" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "phoneNumbers": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + }, + "encoding": { + "phoneNumbers": { + "style": "form" + } + } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/registrationsWithEnumParameter": { + "post": { + "tags": [ + "FromFormParams" + ], + "summary": "Form parameters with description", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Summary for Name", + "example": "MyName" + }, + "phoneNumbers": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Summary for PhoneNumbers" + }, + "logLevel": { + "$ref": "#/components/schemas/LogLevel" + }, + "formFile": { + "type": "string", + "description": "Description for file", + "format": "binary" + }, + "dateTimeKind": { + "$ref": "#/components/schemas/DateTimeKind" + } + } + }, + "encoding": { + "name": { + "style": "form" + }, + "phoneNumbers": { + "style": "form" + }, + "logLevel": { + "style": "form" + }, + "formFile": { + "style": "form" + }, + "dateTimeKind": { + "style": "form" + } + } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/country/validate": { + "get": { + "tags": [ + "FromHeaderParams" + ], + "parameters": [ + { + "name": "country", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/addresses/validate": { + "get": { + "tags": [ + "FromQueryParams" + ], + "parameters": [ + { + "name": "country", + "in": "query", + "description": "3-letter ISO country code", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "city", + "in": "query", + "description": "Name of city", + "schema": { + "type": "string", + "default": "Seattle" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/zip-codes/validate": { + "get": { + "tags": [ + "FromQueryParams" + ], + "parameters": [ + { + "name": "zipCodes", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "search", + "in": "query", + "required": true, + "style": "deepObject", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + }, + "/Issue3013/Get": { + "get": { + "tags": [ + "Issue3013" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/TestResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/TestResponse" + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/promotions": { + "get": { + "tags": [ + "JsonAnnotations" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Promotion" + } + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/shapes": { + "post": { + "tags": [ + "PolymorphicTypes" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Rectangle" + }, + { + "$ref": "#/components/schemas/Circle" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Rectangle" + }, + { + "$ref": "#/components/schemas/Circle" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Rectangle" + }, + { + "$ref": "#/components/schemas/Circle" + } + ] + } + } + }, + "x-purpose": "test" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/orders": { + "post": { + "tags": [ + "ResponseTypeAnnotations" + ], + "summary": "Creates an order", + "requestBody": { + "description": "", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + }, + "required": true, + "x-purpose": "test" + }, + "responses": { + "201": { + "description": "Order created", + "content": { + "application/xml": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "400": { + "description": "Order invalid", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/carts": { + "post": { + "tags": [ + "SwaggerAnnotations" + ], + "operationId": "CreateCart", + "requestBody": { + "description": "The cart request body", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + } + }, + "x-purpose": "test" + }, + "responses": { + "201": { + "description": "The cart was created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + } + } + }, + "400": { + "description": "The cart data is invalid" + } + }, + "x-purpose": "test" + } + }, + "/carts/{id}": { + "get": { + "tags": [ + "SwaggerAnnotations" + ], + "externalDocs": { + "description": "External docs for CartsByIdGet", + "url": "https://tempuri.org/carts-by-id-get" + }, + "operationId": "GetCart", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The cart identifier", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + } + } + } + }, + "x-purpose": "test" + }, + "delete": { + "tags": [ + "SwaggerAnnotations" + ], + "summary": "Deletes a specific cart", + "description": "Requires admin privileges", + "operationId": "DeleteCart", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The cart identifier", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Cart" + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/stores": { + "post": { + "tags": [ + "UnboundParams" + ], + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "location", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "x-purpose": "test" + }, + "get": { + "tags": [ + "UnboundParams" + ], + "parameters": [ + { + "name": "locations", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Store" + } + } + } + } + } + }, + "x-purpose": "test" + } + }, + "/stores/{id}": { + "get": { + "tags": [ + "UnboundParams" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Store" + } + } + } + } + }, + "x-purpose": "test" + }, + "put": { + "tags": [ + "UnboundParams" + ], + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "location", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + }, + "delete": { + "tags": [ + "UnboundParams" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-purpose": "test" + } + } + }, + "components": { + "schemas": { + "Cart": { + "required": [ + "Id" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "The cart identifier", + "format": "int32", + "readOnly": true + }, + "cartType": { + "$ref": "#/components/schemas/CartType" + } + }, + "additionalProperties": false + }, + "CartType": { + "enum": [ + 0, + 1 + ], + "type": "integer", + "description": "The cart type", + "format": "int32" + }, + "Circle": { + "allOf": [ + { + "$ref": "#/components/schemas/Shape" + }, + { + "type": "object", + "properties": { + "radius": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + ] + }, + "CreditCard": { + "required": [ + "cardNumber", + "expMonth", + "expYear" + ], + "type": "object", + "properties": { + "cardNumber": { + "minLength": 1, + "pattern": "^[3-6]?\\d{12,15}$", + "type": "string" + }, + "expMonth": { + "maximum": 12, + "minimum": 1, + "type": "integer", + "format": "int32" + }, + "expYear": { + "maximum": 99, + "minimum": 14, + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DateTimeKind": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "DiscountType": { + "enum": [ + "Percentage", + "Amount" + ], + "type": "string" + }, + "LogLevel": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "type": "integer", + "format": "int32" + }, + "Order": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + }, + "total": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "PaymentRequest": { + "required": [ + "creditCard", + "transaction" + ], + "type": "object", + "properties": { + "transaction": { + "$ref": "#/components/schemas/Transaction" + }, + "creditCard": { + "$ref": "#/components/schemas/CreditCard" + } + }, + "additionalProperties": false + }, + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Uniquely identifies the product", + "format": "int32" + }, + "description": { + "type": "string", + "description": "Describes the product", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/ProductStatus" + }, + "status2": { + "$ref": "#/components/schemas/ProductStatus" + }, + "price": { + "maximum": 122.9, + "exclusiveMaximum": true, + "minimum": 0.1, + "exclusiveMinimum": true, + "type": "number", + "format": "double", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents a product", + "example": { + "id": 123, + "description": "foobar", + "price": 14.37 + } + }, + "ProductStatus": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "Promotion": { + "type": "object", + "properties": { + "promo-code": { + "type": "string", + "nullable": true + }, + "discountType": { + "$ref": "#/components/schemas/DiscountType" + } + }, + "additionalProperties": false + }, + "Rectangle": { + "allOf": [ + { + "$ref": "#/components/schemas/Shape" + }, + { + "type": "object", + "properties": { + "height": { + "type": "integer", + "format": "int32" + }, + "width": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + ] + }, + "Shape": { + "required": [ + "TypeName" + ], + "type": "object", + "properties": { + "TypeName": { + "type": "string" + }, + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "TypeName", + "mapping": { + "Rectangle": "#/components/schemas/Rectangle", + "Circle": "#/components/schemas/Circle" + } + } + }, + "Store": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "location": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TestResponse": { + "type": "object", + "properties": { + "foo": { + "$ref": "#/components/schemas/TestStruct" + } + }, + "additionalProperties": false + }, + "TestStruct": { + "type": "object", + "properties": { + "a": { + "type": "integer", + "format": "int32" + }, + "b": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "Transaction": { + "required": [ + "amount" + ], + "type": "object", + "properties": { + "amount": { + "type": "number", + "format": "double" + }, + "note": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ValidationProblemDetails": { + "type": "object", + "properties": { + "type": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "status": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "detail": { + "type": "string", + "nullable": true + }, + "instance": { + "type": "string", + "nullable": true + }, + "errors": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "nullable": true + } + }, + "additionalProperties": { } + } + } + }, + "tags": [ + { + "name": "CrudActions" + }, + { + "name": "DataAnnotations" + }, + { + "name": "DynamicTypes" + }, + { + "name": "Files" + }, + { + "name": "FromFormParams" + }, + { + "name": "FromHeaderParams" + }, + { + "name": "FromQueryParams" + }, + { + "name": "Issue3013" + }, + { + "name": "JsonAnnotations" + }, + { + "name": "PolymorphicTypes" + }, + { + "name": "ResponseTypeAnnotations" + }, + { + "name": "SwaggerAnnotations", + "description": "Manipulate Carts to your heart's content", + "externalDocs": { + "url": "http://www.tempuri.org" + } + }, + { + "name": "UnboundParams" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index fdafa1de38..97a6f4f1bb 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -1671,12 +1671,48 @@ } }, "tags": [ + { + "name": "CrudActions" + }, + { + "name": "DataAnnotations" + }, + { + "name": "DynamicTypes" + }, + { + "name": "Files" + }, + { + "name": "FromFormParams" + }, + { + "name": "FromHeaderParams" + }, + { + "name": "FromQueryParams" + }, + { + "name": "Issue3013" + }, + { + "name": "JsonAnnotations" + }, + { + "name": "PolymorphicTypes" + }, + { + "name": "ResponseTypeAnnotations" + }, { "name": "SwaggerAnnotations", "description": "Manipulate Carts to your heart's content", "externalDocs": { "url": "http://www.tempuri.org" } + }, + { + "name": "UnboundParams" } ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index fdafa1de38..97a6f4f1bb 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=Basic.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -1671,12 +1671,48 @@ } }, "tags": [ + { + "name": "CrudActions" + }, + { + "name": "DataAnnotations" + }, + { + "name": "DynamicTypes" + }, + { + "name": "Files" + }, + { + "name": "FromFormParams" + }, + { + "name": "FromHeaderParams" + }, + { + "name": "FromQueryParams" + }, + { + "name": "Issue3013" + }, + { + "name": "JsonAnnotations" + }, + { + "name": "PolymorphicTypes" + }, + { + "name": "ResponseTypeAnnotations" + }, { "name": "SwaggerAnnotations", "description": "Manipulate Carts to your heart's content", "externalDocs": { "url": "http://www.tempuri.org" } + }, + { + "name": "UnboundParams" } ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..84b5ecf08c --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,59 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "CliExample", + "version": "1.0" + }, + "servers": [ + { + "url": "http://localhost:51071" + } + ], + "paths": { + "/products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index 1d1afacba0..84b5ecf08c 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index 1d1afacba0..84b5ecf08c 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CliExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..26f06ef714 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,73 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "ConfigFromFile", + "version": "1.0" + }, + "paths": { + "/api/Products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "foo": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + }, + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index 1bc73a344e..26f06ef714 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -64,5 +64,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index 1bc73a344e..26f06ef714 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ConfigFromFile.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -64,5 +64,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomDocumentSerializer.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomDocumentSerializer.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..fb35c79785 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomDocumentSerializer.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,3 @@ +{ + "swagger": "DocumentSerializerTest3.0" +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..72beb1d9f1 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,54 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "CustomUIConfig", + "version": "1.0" + }, + "paths": { + "/products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index f6c887c54d..72beb1d9f1 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -45,5 +45,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index f6c887c54d..72beb1d9f1 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIConfig.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -45,5 +45,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..db2a6f33fe --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,54 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "CustomUIIndex", + "version": "1.0" + }, + "paths": { + "/products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index 5ade11f2a2..db2a6f33fe 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -45,5 +45,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index 5ade11f2a2..db2a6f33fe 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=CustomUIIndex.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -45,5 +45,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..66da63fb97 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,591 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "1" + }, + "paths": { + "/{tenantId}/orders": { + "post": { + "tags": [ + "Orders" + ], + "summary": "Creates a resource", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "The resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Orders" + ], + "summary": "Delete by Ids", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "deleting Ids", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Order" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Order" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deleted", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "404": { + "description": "Failed" + } + } + } + }, + "/{tenantId}/orders/DeleteById": { + "delete": { + "tags": [ + "Orders" + ], + "summary": "Delete by Id", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "deleting Id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deleted", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "404": { + "description": "Failed" + } + } + } + }, + "/{tenantId}/orders/Delete/List": { + "delete": { + "tags": [ + "Orders" + ], + "summary": "Delete by Id List", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "deleting Ids", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Order" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Order" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deleted", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "404": { + "description": "Failed" + } + } + } + }, + "/{tenantId}/products": { + "post": { + "tags": [ + "Products" + ], + "summary": "Creates a resource", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "The resource", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Products" + ], + "summary": "Delete by Ids", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "deleting Ids", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deleted", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "404": { + "description": "Failed" + } + } + } + }, + "/{tenantId}/products/DeleteById": { + "delete": { + "tags": [ + "Products" + ], + "summary": "Delete by Id", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "deleting Id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deleted", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "404": { + "description": "Failed" + } + } + } + }, + "/{tenantId}/products/Delete/List": { + "delete": { + "tags": [ + "Products" + ], + "summary": "Delete by Id List", + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "deleting Ids", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Deleted", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "404": { + "description": "Failed" + } + } + } + } + }, + "components": { + "schemas": { + "Order": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "subtotal": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Orders" + }, + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index 307f1d98ba..66da63fb97 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -579,5 +579,13 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Orders" + }, + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index 307f1d98ba..66da63fb97 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=GenericControllers.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -579,5 +579,13 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Orders" + }, + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet10_0.verified.txt new file mode 100644 index 0000000000..545254baed --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet10_0.verified.txt @@ -0,0 +1,80 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Sample API 1.0", + "version": "1.0" + }, + "paths": { + "/Products": { + "get": { + "tags": [ + "Products" + ], + "parameters": [ + { + "name": "api-version", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet8_0.verified.txt index 7876caa8e1..545254baed 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet8_0.verified.txt @@ -71,5 +71,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet9_0.verified.txt index 7876caa8e1..545254baed 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=1.0.DotNet9_0.verified.txt @@ -71,5 +71,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet10_0.verified.txt new file mode 100644 index 0000000000..fa7ee19c72 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet10_0.verified.txt @@ -0,0 +1,220 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Sample API 2.0", + "version": "2.0" + }, + "paths": { + "/Products": { + "post": { + "tags": [ + "Products" + ], + "parameters": [ + { + "name": "api-version", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "text/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + "get": { + "tags": [ + "Products" + ], + "parameters": [ + { + "name": "api-version", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + }, + "/Products/{id}": { + "put": { + "tags": [ + "Products" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "api-version", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "Products" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "api-version", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet8_0.verified.txt index 2bd3758720..fa7ee19c72 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet8_0.verified.txt @@ -211,5 +211,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet9_0.verified.txt index 2bd3758720..fa7ee19c72 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=MultipleVersions.Startup_swaggerRequestUri=2.0.DotNet9_0.verified.txt @@ -211,5 +211,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..fe357e0e13 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,474 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "NswagClientExample", + "version": "1.0" + }, + "paths": { + "/Animals": { + "post": { + "tags": [ + "Animals" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/SecondLevel": { + "post": { + "tags": [ + "SecondLevel" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SubSubType" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SubSubType" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SubSubType" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + } + } + }, + "/SystemTextJsonAnimals": { + "post": { + "tags": [ + "SystemTextJsonAnimals" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDog" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDog" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDog" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/SystemTextJsonDefaultDiscriminatorAnimals": { + "post": { + "tags": [ + "SystemTextJsonDefaultDiscriminatorAnimals" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Animal": { + "required": [ + "animalType" + ], + "type": "object", + "properties": { + "animalType": { + "$ref": "#/components/schemas/AnimalType" + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "animalType", + "mapping": { + "Cat": "#/components/schemas/Cat", + "Dog": "#/components/schemas/Dog" + } + } + }, + "AnimalType": { + "enum": [ + "Cat", + "Dog" + ], + "type": "string" + }, + "BaseType": { + "required": [ + "discriminator" + ], + "type": "object", + "properties": { + "discriminator": { + "type": "string" + }, + "property": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "discriminator", + "mapping": { + "SubSubType": "#/components/schemas/SubSubType" + } + } + }, + "Cat": { + "allOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "catSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "Dog": { + "allOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "dogSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SubSubType": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseType" + }, + { + "type": "object", + "properties": { + "property2": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonAnimal": { + "required": [ + "animalType" + ], + "type": "object", + "properties": { + "animalType": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "animalType", + "mapping": { + "Cat": "#/components/schemas/SystemTextJsonCat", + "Dog": "#/components/schemas/SystemTextJsonDog" + } + } + }, + "SystemTextJsonCat": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "type": "object", + "properties": { + "catSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonDefaultDiscriminatorAnimal": { + "required": [ + "$type" + ], + "type": "object", + "properties": { + "$type": { + "type": "string" + }, + "animalType": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "$type", + "mapping": { + "Cat": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat", + "Dog": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + } + }, + "SystemTextJsonDefaultDiscriminatorCat": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "type": "object", + "properties": { + "catSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonDefaultDiscriminatorDog": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "type": "object", + "properties": { + "dogSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonDog": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "type": "object", + "properties": { + "dogSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + } + } + }, + "tags": [ + { + "name": "Animals" + }, + { + "name": "SecondLevel" + }, + { + "name": "SystemTextJsonAnimals" + }, + { + "name": "SystemTextJsonDefaultDiscriminatorAnimals" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index 022f86beda..fe357e0e13 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -456,5 +456,19 @@ ] } } - } + }, + "tags": [ + { + "name": "Animals" + }, + { + "name": "SecondLevel" + }, + { + "name": "SystemTextJsonAnimals" + }, + { + "name": "SystemTextJsonDefaultDiscriminatorAnimals" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index 022f86beda..fe357e0e13 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=NSwagClientExample.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -456,5 +456,19 @@ ] } } - } + }, + "tags": [ + { + "name": "Animals" + }, + { + "name": "SecondLevel" + }, + { + "name": "SystemTextJsonAnimals" + }, + { + "name": "SystemTextJsonDefaultDiscriminatorAnimals" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..fcb1f1f2bf --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,252 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API V1", + "version": "v1" + }, + "servers": [ + { + "url": "/resource-server" + } + ], + "paths": { + "/products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "oauth2": [ + "readAccess" + ] + } + ] + }, + "post": { + "tags": [ + "Products" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "oauth2": [ + "writeAccess" + ] + } + ] + } + }, + "/products/{id}": { + "get": { + "tags": [ + "Products" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "oauth2": [ + "readAccess" + ] + } + ] + }, + "delete": { + "tags": [ + "Products" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "oauth2": [ + "writeAccess" + ] + } + ] + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "serialNo": { + "type": "string", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/ProductStatus" + } + }, + "additionalProperties": false + }, + "ProductStatus": { + "enum": [ + 0, + 1 + ], + "type": "integer", + "format": "int32" + } + }, + "securitySchemes": { + "oauth2": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "authorizationUrl": "/auth-server/connect/authorize", + "tokenUrl": "/auth-server/connect/token", + "scopes": { + "readAccess": "Access read operations", + "writeAccess": "Access write operations" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "readAccess", + "writeAccess" + ] + } + ], + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index 433d6bf6ff..fcb1f1f2bf 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -243,5 +243,10 @@ "writeAccess" ] } + ], + "tags": [ + { + "name": "Products" + } ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index 433d6bf6ff..fcb1f1f2bf 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=OAuth2Integration.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -243,5 +243,10 @@ "writeAccess" ] } + ], + "tags": [ + { + "name": "Products" + } ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..4a46d91284 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,194 @@ +{ + "swagger": "2.0", + "info": { + "title": "ReDoc", + "version": "1.0" + }, + "paths": { + "/products": { + "post": { + "tags": [ + "Products" + ], + "consumes": [ + "application/json", + "text/json", + "application/*+json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Product" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "get": { + "tags": [ + "Products" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Product" + } + } + } + } + } + }, + "/products/{id}": { + "get": { + "tags": [ + "Products" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Product" + } + } + } + }, + "put": { + "tags": [ + "Products" + ], + "consumes": [ + "application/json", + "text/json", + "application/*+json" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Product" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "patch": { + "tags": [ + "Products" + ], + "consumes": [ + "application/json", + "text/json", + "application/*+json" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": { } + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "tags": [ + "Products" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "definitions": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "x-nullable": true + } + }, + "additionalProperties": false + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt index 27a5d6cfb0..4a46d91284 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -32,8 +32,8 @@ "200": { "description": "OK", "schema": { - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" } } } @@ -175,14 +175,20 @@ "type": "object", "properties": { "id": { - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" }, "description": { - "type": "string" + "type": "string", + "x-nullable": true } }, "additionalProperties": false } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt index 27a5d6cfb0..4a46d91284 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=ReDoc.Startup_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -32,8 +32,8 @@ "200": { "description": "OK", "schema": { - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" } } } @@ -175,14 +175,20 @@ "type": "object", "properties": { "id": { - "format": "int32", - "type": "integer" + "type": "integer", + "format": "int32" }, "description": { - "type": "string" + "type": "string", + "x-nullable": true } }, "additionalProperties": false } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=TestFirst.Startup_swaggerRequestUri=v1-generated.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=TestFirst.Startup_swaggerRequestUri=v1-generated.DotNet10_0.verified.txt new file mode 100644 index 0000000000..5dc02708a7 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.SwaggerEndpoint_ReturnsValidSwaggerJson_startupType=TestFirst.Startup_swaggerRequestUri=v1-generated.DotNet10_0.verified.txt @@ -0,0 +1,52 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test-first Example API (Generated)", + "version": "v1" + }, + "paths": { + "/api/users": { + "post": { + "operationId": "CreateUser", + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": [ + "email", + "password" + ], + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string" + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "User created", + "headers": { + "Location": { + "required": true, + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid request" + } + } + } + } + } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..14e9ac594f --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,79 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "MinimalApp", + "version": "v1" + }, + "paths": { + "/WeatherForecast": { + "get": { + "tags": [ + "WeatherForecast" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WeatherForecast" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WeatherForecast" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WeatherForecast" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "WeatherForecast": { + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date-time" + }, + "temperatureC": { + "type": "integer", + "format": "int32" + }, + "temperatureF": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "summary": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "WeatherForecast" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt index 7c2cec82e4..14e9ac594f 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -70,5 +70,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "WeatherForecast" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt index 7c2cec82e4..14e9ac594f 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MinimalApp.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -70,5 +70,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "WeatherForecast" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..c02949b557 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,87 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "MvcWithNullable", + "version": "1.0" + }, + "paths": { + "/api/Enum": { + "get": { + "tags": [ + "Enum" + ], + "parameters": [ + { + "name": "logLevel", + "in": "query", + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/LogLevel" + } + ], + "default": 4 + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/RequiredEnum": { + "get": { + "tags": [ + "RequiredEnum" + ], + "parameters": [ + { + "name": "logLevel", + "in": "query", + "required": true, + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/LogLevel" + } + ], + "default": 4 + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "LogLevel": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "type": "integer", + "format": "int32" + } + } + }, + "tags": [ + { + "name": "Enum" + }, + { + "name": "RequiredEnum" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt index ac23e23151..c02949b557 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -75,5 +75,13 @@ "format": "int32" } } - } + }, + "tags": [ + { + "name": "Enum" + }, + { + "name": "RequiredEnum" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt index ac23e23151..c02949b557 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=MvcWithNullable.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -75,5 +75,13 @@ "format": "int32" } } - } + }, + "tags": [ + { + "name": "Enum" + }, + { + "name": "RequiredEnum" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=TopLevelSwaggerDoc.Program_swaggerRequestUri=.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=TopLevelSwaggerDoc.Program_swaggerRequestUri=.DotNet10_0.verified.txt new file mode 100644 index 0000000000..7f373c459d --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=TopLevelSwaggerDoc.Program_swaggerRequestUri=.DotNet10_0.verified.txt @@ -0,0 +1,9 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "1" + }, + "paths": { }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..48d906e2bc --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,87 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Native AoT API V1", + "description": "A sample API for testing Swashbuckle with native AoT", + "termsOfService": "http://tempuri.org/terms", + "version": "v1" + }, + "paths": { + "/todos": { + "get": { + "tags": [ + "WebApi.Aot" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Todo" + } + } + } + } + } + } + } + }, + "/todos/{id}": { + "get": { + "tags": [ + "WebApi.Aot" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Todo": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "title": { + "type": "string", + "nullable": true + }, + "dueBy": { + "type": "string", + "format": "date", + "nullable": true + }, + "isComplete": { + "type": "boolean" + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "WebApi.Aot" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt index 579ea114e7..48d906e2bc 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -78,5 +78,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "WebApi.Aot" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt index 579ea114e7..48d906e2bc 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Aot.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -78,5 +78,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "WebApi.Aot" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt new file mode 100644 index 0000000000..048170ae70 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet10_0.verified.txt @@ -0,0 +1,1220 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "WebApi", + "version": "v1" + }, + "paths": { + "/annotations/fruit/{id}": { + "post": { + "tags": [ + "Annotations" + ], + "summary": "CreateFruit", + "description": "Create a fruit", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The id of the fruit that will be created", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Description for Body", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Fruit" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Description for response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Fruit" + } + } + } + } + } + } + }, + "/annotations/singleForm": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/PersonAnnotated" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PersonAnnotated" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/multipleForms": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "$ref": "#/components/schemas/AddressAnnotated" + } + ] + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "$ref": "#/components/schemas/AddressAnnotated" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/IFromFileAndString": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file", + "tags" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "description": "Description for File", + "format": "binary" + }, + "tags": { + "type": "string" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/IFromFileAndEnum": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "dateTimeKind", + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "dateTimeKind": { + "$ref": "#/components/schemas/DateTimeKind" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "dateTimeKind": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/IFromObjectAndString": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/AsParameters": { + "get": { + "tags": [ + "Annotations" + ], + "parameters": [ + { + "name": "paramOne", + "in": "query", + "description": "Description", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "paramTwo", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "paramThree", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "paramFour", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "paramFive", + "in": "query", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "paramSix", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "paramSeven", + "in": "query", + "schema": { + "type": "string", + "format": "time" + } + }, + { + "name": "paramEight", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "time" + } + }, + { + "name": "paramNine", + "in": "query", + "schema": { + "$ref": "#/components/schemas/DateTimeKind" + } + }, + { + "name": "paramTen", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/DateTimeKind" + } + }, + { + "name": "paramEleven", + "in": "query", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "paramTwelve", + "in": "query", + "required": true, + "schema": { + "type": "number", + "format": "double" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsParametersRecord" + } + } + } + } + } + } + }, + "/TypeWithTryParse/{tryParse}": { + "get": { + "tags": [ + "WebApi" + ], + "parameters": [ + { + "name": "tryParse", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/weatherforecast": { + "get": { + "tags": [ + "WithOpenApi" + ], + "operationId": "GetWeatherForecast", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WeatherForecast" + } + } + } + } + } + } + } + }, + "/WithOpenApi/multipleForms": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "$ref": "#/components/schemas/Address" + } + ] + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "$ref": "#/components/schemas/Address" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFile": { + "post": { + "tags": [ + "WithOpenApi" + ], + "parameters": [ + { + "name": "queryParameter", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + }, + "encoding": { + "file": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFileCollection": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "collection" + ], + "type": "object", + "properties": { + "collection": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + } + } + }, + "encoding": { + "collection": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromBody": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationCustomExchangeRatesDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFileAndString": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file", + "tags" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "tags": { + "type": "string" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFileAndEnum": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "dateTimeKind", + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "dateTimeKind": { + "$ref": "#/components/schemas/DateTimeKind" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "dateTimeKind": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromObjectAndString": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/XmlComments/Car/{id}": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The product id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 111 + } + ], + "responses": { + "200": { + "description": "A Product Id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "/XmlComments/Car": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product using asParameters record", + "parameters": [ + { + "name": "Id", + "in": "query", + "description": "Uniquely identifies the product", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "Description", + "in": "query", + "description": "Describes the product", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "A Product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "/XmlComments/CarWithProduces": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product With Produces attribute", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "A Product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "/XmlComments/CarWithProducesDefaultResponseType": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product With ProducesDefaultResponseType attribute", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "default": { + "description": "A Product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Address": { + "type": "object", + "properties": { + "street": { + "type": "string", + "nullable": true + }, + "city": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "nullable": true + }, + "zipCode": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AddressAnnotated": { + "type": "object", + "properties": { + "street": { + "type": "string", + "description": "Description for Street", + "nullable": true + }, + "city": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "nullable": true + }, + "zipCode": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AsParametersRecord": { + "type": "object", + "properties": { + "paramOne": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "paramTwo": { + "type": "string", + "format": "uuid" + }, + "paramThree": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "paramFour": { + "type": "string", + "format": "date-time" + }, + "paramFive": { + "type": "string", + "format": "date", + "nullable": true + }, + "paramSix": { + "type": "string", + "format": "date" + }, + "paramSeven": { + "type": "string", + "format": "time", + "nullable": true + }, + "paramEight": { + "type": "string", + "format": "time" + }, + "paramNine": { + "$ref": "#/components/schemas/DateTimeKind" + }, + "paramTen": { + "$ref": "#/components/schemas/DateTimeKind" + }, + "paramEleven": { + "type": "number", + "format": "double", + "nullable": true + }, + "paramTwelve": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "CurrenciesRate": { + "required": [ + "currencyFrom", + "currencyTo" + ], + "type": "object", + "properties": { + "currencyFrom": { + "type": "string", + "description": "Currency From", + "nullable": true + }, + "currencyTo": { + "type": "string", + "nullable": true + }, + "rate": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "DateTimeKind": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "Fruit": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Description for Schema" + }, + "OrganizationCustomExchangeRatesDto": { + "required": [ + "currenciesRates" + ], + "type": "object", + "properties": { + "currenciesRates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CurrenciesRate" + }, + "nullable": true + }, + "isUpdated": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "Person": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "nullable": true + }, + "lastName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PersonAnnotated": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "Description for FirstName", + "nullable": true + }, + "lastName": { + "type": "string", + "description": "Description for LastName", + "nullable": true + } + }, + "additionalProperties": false + }, + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Uniquely identifies the product", + "format": "int32" + }, + "description": { + "type": "string", + "description": "Describes the product", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents a product" + }, + "WeatherForecast": { + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date" + }, + "temperatureC": { + "type": "integer", + "format": "int32" + }, + "summary": { + "type": "string", + "nullable": true + }, + "temperatureF": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Annotations" + }, + { + "name": "WebApi" + }, + { + "name": "WithOpenApi" + }, + { + "name": "Xml" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt index d437eea1cf..6e9b065305 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet8_0.verified.txt @@ -505,8 +505,7 @@ ] } } - }, - "required": true + } }, "responses": { "200": { @@ -531,7 +530,6 @@ { "name": "queryParameter", "in": "query", - "description": "queryParameter Description", "required": true, "schema": { "type": "string" @@ -559,8 +557,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -605,8 +602,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -684,8 +680,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -734,8 +729,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -808,8 +802,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -1097,5 +1090,19 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Annotations" + }, + { + "name": "WebApi" + }, + { + "name": "WithOpenApi" + }, + { + "name": "Xml" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt index d437eea1cf..6e9b065305 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.Swagger_IsValidJson_No_Startup_entryPointType=WebApi.Program_swaggerRequestUri=v1.DotNet9_0.verified.txt @@ -505,8 +505,7 @@ ] } } - }, - "required": true + } }, "responses": { "200": { @@ -531,7 +530,6 @@ { "name": "queryParameter", "in": "query", - "description": "queryParameter Description", "required": true, "schema": { "type": "string" @@ -559,8 +557,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -605,8 +602,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -684,8 +680,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -734,8 +729,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -808,8 +802,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -1097,5 +1090,19 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Annotations" + }, + { + "name": "WebApi" + }, + { + "name": "WithOpenApi" + }, + { + "name": "Xml" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet10_0.verified.txt new file mode 100644 index 0000000000..048170ae70 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet10_0.verified.txt @@ -0,0 +1,1220 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "WebApi", + "version": "v1" + }, + "paths": { + "/annotations/fruit/{id}": { + "post": { + "tags": [ + "Annotations" + ], + "summary": "CreateFruit", + "description": "Create a fruit", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The id of the fruit that will be created", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Description for Body", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Fruit" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Description for response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Fruit" + } + } + } + } + } + } + }, + "/annotations/singleForm": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/PersonAnnotated" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PersonAnnotated" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/multipleForms": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "$ref": "#/components/schemas/AddressAnnotated" + } + ] + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "$ref": "#/components/schemas/AddressAnnotated" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/IFromFileAndString": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file", + "tags" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "description": "Description for File", + "format": "binary" + }, + "tags": { + "type": "string" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/IFromFileAndEnum": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "dateTimeKind", + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "dateTimeKind": { + "$ref": "#/components/schemas/DateTimeKind" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "dateTimeKind": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/IFromObjectAndString": { + "post": { + "tags": [ + "Annotations" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/PersonAnnotated" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/annotations/AsParameters": { + "get": { + "tags": [ + "Annotations" + ], + "parameters": [ + { + "name": "paramOne", + "in": "query", + "description": "Description", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "paramTwo", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "paramThree", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "paramFour", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "paramFive", + "in": "query", + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "paramSix", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "date" + } + }, + { + "name": "paramSeven", + "in": "query", + "schema": { + "type": "string", + "format": "time" + } + }, + { + "name": "paramEight", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "time" + } + }, + { + "name": "paramNine", + "in": "query", + "schema": { + "$ref": "#/components/schemas/DateTimeKind" + } + }, + { + "name": "paramTen", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/DateTimeKind" + } + }, + { + "name": "paramEleven", + "in": "query", + "schema": { + "type": "number", + "format": "double" + } + }, + { + "name": "paramTwelve", + "in": "query", + "required": true, + "schema": { + "type": "number", + "format": "double" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsParametersRecord" + } + } + } + } + } + } + }, + "/TypeWithTryParse/{tryParse}": { + "get": { + "tags": [ + "WebApi" + ], + "parameters": [ + { + "name": "tryParse", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/weatherforecast": { + "get": { + "tags": [ + "WithOpenApi" + ], + "operationId": "GetWeatherForecast", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WeatherForecast" + } + } + } + } + } + } + } + }, + "/WithOpenApi/multipleForms": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "$ref": "#/components/schemas/Address" + } + ] + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "$ref": "#/components/schemas/Address" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFile": { + "post": { + "tags": [ + "WithOpenApi" + ], + "parameters": [ + { + "name": "queryParameter", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + }, + "encoding": { + "file": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFileCollection": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "collection" + ], + "type": "object", + "properties": { + "collection": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + } + } + }, + "encoding": { + "collection": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromBody": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationCustomExchangeRatesDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFileAndString": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "file", + "tags" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "tags": { + "type": "string" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromFileAndEnum": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "dateTimeKind", + "file" + ], + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "dateTimeKind": { + "$ref": "#/components/schemas/DateTimeKind" + } + } + }, + "encoding": { + "file": { + "style": "form" + }, + "dateTimeKind": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/WithOpenApi/IFromObjectAndString": { + "post": { + "tags": [ + "WithOpenApi" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Person" + }, + { + "required": [ + "tags" + ], + "type": "object", + "properties": { + "tags": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "tags": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/XmlComments/Car/{id}": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The product id", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 111 + } + ], + "responses": { + "200": { + "description": "A Product Id", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "/XmlComments/Car": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product using asParameters record", + "parameters": [ + { + "name": "Id", + "in": "query", + "description": "Uniquely identifies the product", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "Description", + "in": "query", + "description": "Describes the product", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "A Product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "/XmlComments/CarWithProduces": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product With Produces attribute", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "A Product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + }, + "/XmlComments/CarWithProducesDefaultResponseType": { + "get": { + "tags": [ + "Xml" + ], + "summary": "Returns a specific product With ProducesDefaultResponseType attribute", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + }, + "default": { + "description": "A Product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Address": { + "type": "object", + "properties": { + "street": { + "type": "string", + "nullable": true + }, + "city": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "nullable": true + }, + "zipCode": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AddressAnnotated": { + "type": "object", + "properties": { + "street": { + "type": "string", + "description": "Description for Street", + "nullable": true + }, + "city": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "nullable": true + }, + "zipCode": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AsParametersRecord": { + "type": "object", + "properties": { + "paramOne": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "paramTwo": { + "type": "string", + "format": "uuid" + }, + "paramThree": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "paramFour": { + "type": "string", + "format": "date-time" + }, + "paramFive": { + "type": "string", + "format": "date", + "nullable": true + }, + "paramSix": { + "type": "string", + "format": "date" + }, + "paramSeven": { + "type": "string", + "format": "time", + "nullable": true + }, + "paramEight": { + "type": "string", + "format": "time" + }, + "paramNine": { + "$ref": "#/components/schemas/DateTimeKind" + }, + "paramTen": { + "$ref": "#/components/schemas/DateTimeKind" + }, + "paramEleven": { + "type": "number", + "format": "double", + "nullable": true + }, + "paramTwelve": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "CurrenciesRate": { + "required": [ + "currencyFrom", + "currencyTo" + ], + "type": "object", + "properties": { + "currencyFrom": { + "type": "string", + "description": "Currency From", + "nullable": true + }, + "currencyTo": { + "type": "string", + "nullable": true + }, + "rate": { + "type": "number", + "format": "double" + } + }, + "additionalProperties": false + }, + "DateTimeKind": { + "enum": [ + 0, + 1, + 2 + ], + "type": "integer", + "format": "int32" + }, + "Fruit": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Description for Schema" + }, + "OrganizationCustomExchangeRatesDto": { + "required": [ + "currenciesRates" + ], + "type": "object", + "properties": { + "currenciesRates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CurrenciesRate" + }, + "nullable": true + }, + "isUpdated": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "Person": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "nullable": true + }, + "lastName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PersonAnnotated": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "Description for FirstName", + "nullable": true + }, + "lastName": { + "type": "string", + "description": "Description for LastName", + "nullable": true + } + }, + "additionalProperties": false + }, + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Uniquely identifies the product", + "format": "int32" + }, + "description": { + "type": "string", + "description": "Describes the product", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Represents a product" + }, + "WeatherForecast": { + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date" + }, + "temperatureC": { + "type": "integer", + "format": "int32" + }, + "summary": { + "type": "string", + "nullable": true + }, + "temperatureF": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Annotations" + }, + { + "name": "WebApi" + }, + { + "name": "WithOpenApi" + }, + { + "name": "Xml" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet8_0.verified.txt index d437eea1cf..6e9b065305 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet8_0.verified.txt @@ -505,8 +505,7 @@ ] } } - }, - "required": true + } }, "responses": { "200": { @@ -531,7 +530,6 @@ { "name": "queryParameter", "in": "query", - "description": "queryParameter Description", "required": true, "schema": { "type": "string" @@ -559,8 +557,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -605,8 +602,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -684,8 +680,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -734,8 +729,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -808,8 +802,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -1097,5 +1090,19 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Annotations" + }, + { + "name": "WebApi" + }, + { + "name": "WithOpenApi" + }, + { + "name": "Xml" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet9_0.verified.txt index d437eea1cf..6e9b065305 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/snapshots/VerifyTests.TypesAreRenderedCorrectly.DotNet9_0.verified.txt @@ -505,8 +505,7 @@ ] } } - }, - "required": true + } }, "responses": { "200": { @@ -531,7 +530,6 @@ { "name": "queryParameter", "in": "query", - "description": "queryParameter Description", "required": true, "schema": { "type": "string" @@ -559,8 +557,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -605,8 +602,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -684,8 +680,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -734,8 +729,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -808,8 +802,7 @@ } } } - }, - "required": true + } }, "responses": { "200": { @@ -1097,5 +1090,19 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Annotations" + }, + { + "name": "WebApi" + }, + { + "name": "WithOpenApi" + }, + { + "name": "Xml" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/RecursiveCallSchemaFilter.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/RecursiveCallSchemaFilter.cs index 763bc346da..5551799107 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/RecursiveCallSchemaFilter.cs +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/RecursiveCallSchemaFilter.cs @@ -1,11 +1,11 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Newtonsoft.Test; public class RecursiveCallSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema model, SchemaFilterContext context) + public void Apply(IOpenApiSchema model, SchemaFilterContext context) { if (model.Type == JsonSchemaTypes.Object) { diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/VendorExtensionsSchemaFilter.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/VendorExtensionsSchemaFilter.cs index 02a8ea7311..d9ca102ba0 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/VendorExtensionsSchemaFilter.cs +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/VendorExtensionsSchemaFilter.cs @@ -1,13 +1,16 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Swashbuckle.AspNetCore.Newtonsoft.Test; public class VendorExtensionsSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { - schema.Extensions.Add("X-foo", new OpenApiString("bar")); + if (schema is OpenApiSchema openApiSchema) + { + openApiSchema.Extensions ??= new Dictionary(); + openApiSchema.Extensions.Add("X-foo", new JsonNodeExtension("bar")); + } } } diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs index dbe50b446b..1e3a76f7b4 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.NewtonsoftJson; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; @@ -14,8 +14,6 @@ using Swashbuckle.AspNetCore.SwaggerGen.Test.Fixtures; using Swashbuckle.AspNetCore.TestSupport; -using JsonSchemaType = string; - namespace Swashbuckle.AspNetCore.Newtonsoft.Test; public class NewtonsoftSchemaGeneratorTests @@ -57,16 +55,16 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type) { typeof(Version), JsonSchemaTypes.String, null }, { typeof(DateOnly), JsonSchemaTypes.String, "date" }, { typeof(TimeOnly), JsonSchemaTypes.String, "time" }, - { typeof(bool?), JsonSchemaTypes.Boolean, null }, - { typeof(int?), JsonSchemaTypes.Integer, "int32" }, - { typeof(DateTime?), JsonSchemaTypes.String, "date-time" }, - { typeof(Guid?), JsonSchemaTypes.String, "uuid" }, - { typeof(DateOnly?), JsonSchemaTypes.String, "date" }, - { typeof(TimeOnly?), JsonSchemaTypes.String, "time" }, + { typeof(bool?), JsonSchemaTypes.Boolean | JsonSchemaType.Null, null }, + { typeof(int?), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int32" }, + { typeof(DateTime?), JsonSchemaTypes.String | JsonSchemaType.Null, "date-time" }, + { typeof(Guid?), JsonSchemaTypes.String | JsonSchemaType.Null, "uuid" }, + { typeof(DateOnly?), JsonSchemaTypes.String | JsonSchemaType.Null, "date" }, + { typeof(TimeOnly?), JsonSchemaTypes.String | JsonSchemaType.Null, "time" }, { typeof(Int128), JsonSchemaTypes.Integer, "int128" }, - { typeof(Int128?), JsonSchemaTypes.Integer, "int128" }, + { typeof(Int128?), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int128" }, { typeof(UInt128), JsonSchemaTypes.Integer, "int128" }, - { typeof(UInt128?), JsonSchemaTypes.Integer, "int128" }, + { typeof(UInt128?), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int128" }, }; [Theory] @@ -100,7 +98,7 @@ public void GenerateSchema_GeneratesReferencedEnumSchema_IfEnumOrNullableEnumTyp { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(type, schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(type, schemaRepository)); Assert.NotNull(referenceSchema.Reference); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; @@ -116,7 +114,7 @@ public void GenerateSchema_DedupsEnumValues_IfEnumTypeHasDuplicateValues() var enumType = typeof(HttpStatusCode); var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(enumType, schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(enumType, schemaRepository)); Assert.NotNull(referenceSchema.Reference); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; @@ -161,24 +159,28 @@ public void GenerateSchema_GeneratesReferencedDictionarySchema_IfDictionaryTypeI { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(DictionaryOfSelf), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(DictionaryOfSelf), schemaRepository)); Assert.NotNull(referenceSchema.Reference); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); Assert.True(schema.AdditionalPropertiesAllowed); Assert.NotNull(schema.AdditionalProperties); - Assert.Equal(schema.AdditionalProperties.Reference.Id, referenceSchema.Reference.Id); // ref to self + Assert.Equal(Assert.IsType(schema.AdditionalProperties).Reference.Id, referenceSchema.Reference.Id); // ref to self } #nullable enable public static TheoryData EnumerableTypesData => new() { { typeof(int[]), JsonSchemaTypes.Integer, "int32" }, + { typeof(int?[]), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int32" }, + { typeof(double[]), JsonSchemaTypes.Number, "double" }, + { typeof(double?[]), JsonSchemaTypes.Number | JsonSchemaType.Null, "double" }, + { typeof(DateTime[]), JsonSchemaTypes.String, "date-time" }, + { typeof(DateTime?[]), JsonSchemaTypes.String | JsonSchemaType.Null, "date-time" }, { typeof(IEnumerable), JsonSchemaTypes.String, null }, - { typeof(DateTime?[]), JsonSchemaTypes.String, "date-time" }, { typeof(int[][]), JsonSchemaTypes.Array, null }, - { typeof(IList), null, null } + { typeof(IList), null, null }, }; [Theory] @@ -214,12 +216,12 @@ public void GenerateSchema_GeneratesReferencedArraySchema_IfEnumerableTypeIsSelf { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(ListOfSelf), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(ListOfSelf), schemaRepository)); Assert.NotNull(referenceSchema.Reference); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(JsonSchemaTypes.Array, schema.Type); - Assert.Equal(schema.Items.Reference.Id, referenceSchema.Reference.Id); // ref to self + Assert.Equal(Assert.IsType(schema.Items).Reference.Id, referenceSchema.Reference.Id); // ref to self } [Theory] @@ -234,7 +236,7 @@ public void GenerateSchema_GeneratesReferencedObjectSchema_IfComplexType( { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(type, schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(type, schemaRepository)); Assert.NotNull(referenceSchema.Reference); Assert.Equal(expectedSchemaId, referenceSchema.Reference.Id); @@ -249,7 +251,7 @@ public void GenerateSchema_IncludesInheritedProperties_IfComplexTypeIsDerived() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(SubType1), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(SubType1), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); @@ -261,7 +263,7 @@ public void GenerateSchema_ExcludesIndexerProperties_IfComplexTypeIsIndexed() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(IndexedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(IndexedType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); @@ -279,10 +281,10 @@ public void GenerateSchema_SetsNullableFlag_IfPropertyIsReferenceOrNullableType( { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(declaringType, schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(declaringType, schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.Equal(expectedNullable, schema.Properties[propertyName].Nullable); + Assert.Equal(expectedNullable, schema.Properties[propertyName].Type.Value.HasFlag(JsonSchemaType.Null)); } [Fact] @@ -292,10 +294,14 @@ public void GenerateSchema_DoesNotSetNullableFlag_IfReferencedEnum() var referenceSchema = Subject().GenerateSchema(typeof(TypeWithNullableProperties), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; + const string propertyName = nameof(TypeWithNullableProperties.NullableIntEnumProperty); - Assert.False(schema.Properties[propertyName].Nullable); - Assert.Equal("IntEnum", schema.Properties[propertyName].Reference.Id); + Assert.False(schema.Properties[propertyName].Type.HasValue); + + reference = Assert.IsType(schema.Properties[propertyName]); + Assert.Equal("IntEnum", reference.Reference.Id); } [Fact] @@ -305,8 +311,9 @@ public void GenerateSchema_SetNullableFlag_IfInlineEnum() var referenceSchema = Subject(o => o.UseInlineDefinitionsForEnums = true).GenerateSchema(typeof(TypeWithNullableProperties), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.True(schema.Properties[nameof(TypeWithNullableProperties.NullableIntEnumProperty)].Nullable); + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; + Assert.True(schema.Properties[nameof(TypeWithNullableProperties.NullableIntEnumProperty)].Type.Value.HasFlag(JsonSchemaType.Null)); } [Theory] @@ -320,7 +327,7 @@ public void GenerateSchema_SetNullableFlag_IfInlineEnum() [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.IntArrayWithDefault), "[\n 1,\n 2,\n 3\n]")] [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.StringArrayWithDefault), "[\n \"foo\",\n \"bar\"\n]")] [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.NullableIntWithDefaultValue), "2147483647")] - [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.NullableIntWithDefaultNullValue), "null")] + [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.NullableIntWithDefaultNullValue), null)] public void GenerateSchema_SetsDefault_IfPropertyHasDefaultValueAttribute( Type declaringType, string propertyName, @@ -332,7 +339,7 @@ public void GenerateSchema_SetsDefault_IfPropertyHasDefaultValueAttribute( var schemaRepository = new SchemaRepository(); // Act - var referenceSchema = Subject().GenerateSchema(declaringType, schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(declaringType, schemaRepository)); // Assert var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; @@ -345,7 +352,7 @@ public void GenerateSchema_SetsDeprecatedFlag_IfPropertyHasObsoleteAttribute() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(TypeWithObsoleteAttribute), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(TypeWithObsoleteAttribute), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.True(schema.Properties["ObsoleteProperty"].Deprecated); @@ -358,7 +365,7 @@ public void GenerateSchema_SetsValidationProperties_IfComplexTypeHasValidationAt { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(type, schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(type, schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal("credit-card", schema.Properties["StringWithDataTypeCreditCard"].Format); @@ -370,26 +377,28 @@ public void GenerateSchema_SetsValidationProperties_IfComplexTypeHasValidationAt Assert.Equal(3, schema.Properties["StringWithLength"].MaxLength); Assert.Equal(1, schema.Properties["ArrayWithLength"].MinItems); Assert.Equal(3, schema.Properties["ArrayWithLength"].MaxItems); - Assert.Equal(true, schema.Properties["IntWithExclusiveRange"].ExclusiveMinimum); - Assert.Equal(true, schema.Properties["IntWithExclusiveRange"].ExclusiveMaximum); + Assert.NotNull(schema.Properties["IntWithExclusiveRange"].ExclusiveMinimum); + Assert.NotNull(schema.Properties["IntWithExclusiveRange"].ExclusiveMaximum); Assert.Equal("byte", schema.Properties["StringWithBase64"].Format); - Assert.Equal(JsonSchemaTypes.String, schema.Properties["StringWithBase64"].Type); + Assert.Equal(JsonSchemaTypes.String | JsonSchemaType.Null, schema.Properties["StringWithBase64"].Type); Assert.Null(schema.Properties["IntWithRange"].ExclusiveMinimum); Assert.Null(schema.Properties["IntWithRange"].ExclusiveMaximum); - Assert.Equal(1, schema.Properties["IntWithRange"].Minimum); - Assert.Equal(10, schema.Properties["IntWithRange"].Maximum); + Assert.Equal("1", schema.Properties["IntWithRange"].Minimum); + Assert.Equal("10", schema.Properties["IntWithRange"].Maximum); Assert.Equal("^[3-6]?\\d{12,15}$", schema.Properties["StringWithRegularExpression"].Pattern); Assert.Equal(5, schema.Properties["StringWithStringLength"].MinLength); Assert.Equal(10, schema.Properties["StringWithStringLength"].MaxLength); Assert.Equal(1, schema.Properties["StringWithRequired"].MinLength); - Assert.False(schema.Properties["StringWithRequired"].Nullable); - Assert.False(schema.Properties["StringWithRequiredAllowEmptyTrue"].Nullable); + Assert.False(schema.Properties["StringWithRequired"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["StringWithRequiredAllowEmptyTrue"].Type.Value.HasFlag(JsonSchemaType.Null)); Assert.Null(schema.Properties["StringWithRequiredAllowEmptyTrue"].MinLength); Assert.Equal(["NullableIntEnumWithRequired", "StringWithRequired", "StringWithRequiredAllowEmptyTrue"], schema.Required); Assert.Equal("Description", schema.Properties[nameof(TypeWithValidationAttributes.StringWithDescription)].Description); Assert.True(schema.Properties[nameof(TypeWithValidationAttributes.StringWithReadOnly)].ReadOnly); - Assert.False(schema.Properties[nameof(TypeWithValidationAttributes.NullableIntEnumWithRequired)].Nullable); - Assert.Equal(nameof(IntEnum), schema.Properties[nameof(TypeWithValidationAttributes.NullableIntEnumWithRequired)].Reference.Id); + + var reference = Assert.IsType(schema.Properties[nameof(TypeWithValidationAttributes.NullableIntEnumWithRequired)]); + Assert.False(reference.Type.HasValue); + Assert.Equal(nameof(IntEnum), reference.Reference.Id); } [Fact] @@ -397,7 +406,7 @@ public void GenerateSchema_SetsReadOnlyAndWriteOnlyFlags_IfPropertyIsRestricted( { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(TypeWithRestrictedProperties), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(TypeWithRestrictedProperties), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.False(schema.Properties["ReadWriteProperty"].ReadOnly); @@ -413,7 +422,7 @@ public void GenerateSchema_DoesNotSetReadOnlyFlag_IfPropertyIsReadOnlyButCanBeSe { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(TypeWithPropertiesSetViaConstructor), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(TypeWithPropertiesSetViaConstructor), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.False(schema.Properties["Id"].ReadOnly); @@ -434,7 +443,7 @@ public void GenerateSchema_SupportsOption_CustomTypeMappings( var schema = subject.GenerateSchema(type, new SchemaRepository()); Assert.Equal(JsonSchemaTypes.String, schema.Type); - Assert.Empty(schema.Properties); + Assert.Null(schema.Properties); } [Theory] @@ -451,10 +460,14 @@ public void GenerateSchema_SupportsOption_SchemaFilters(Type type) var schema = subject.GenerateSchema(type, schemaRepository); - if (schema.Reference == null) - Assert.Contains("X-foo", schema.Extensions.Keys); + if (schema is OpenApiSchemaReference reference) + { + Assert.Contains("X-foo", schemaRepository.Schemas[reference.Reference.Id].Extensions.Keys); + } else - Assert.Contains("X-foo", schemaRepository.Schemas[schema.Reference.Id].Extensions.Keys); + { + Assert.Contains("X-foo", schema.Extensions.Keys); + } } [Fact] @@ -465,7 +478,7 @@ public void GenerateSchema_SupportsOption_IgnoreObsoleteProperties() ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(TypeWithObsoleteAttribute), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(TypeWithObsoleteAttribute), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.DoesNotContain("ObsoleteProperty", schema.Properties.Keys); @@ -479,7 +492,7 @@ public void GenerateSchema_SupportsOption_SchemaIdSelector() ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(ComplexType), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(ComplexType), schemaRepository)); Assert.Equal("Swashbuckle.AspNetCore.TestSupport.ComplexType", referenceSchema.Reference.Id); Assert.Contains(referenceSchema.Reference.Id, schemaRepository.Schemas.Keys); @@ -493,14 +506,13 @@ public void GenerateSchema_SupportsOption_UseAllOfForInheritance() ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(SubType1), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(SubType1), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.NotNull(schema.AllOf); Assert.Equal(2, schema.AllOf.Count); - var baseSchema = schema.AllOf[0]; + var baseSchema = Assert.IsType(schema.AllOf[0]); Assert.Equal("BaseType", baseSchema.Reference.Id); - Assert.NotNull(baseSchema.Reference); var subSchema = schema.AllOf[1]; Assert.Equal(["Property1"], subSchema.Properties.Keys); // The base type schema @@ -536,7 +548,7 @@ public void GenerateSchema_SupportsOption_DiscriminatorNameSelector() var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(BaseType), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(BaseType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Contains("TypeName", schema.Properties.Keys); @@ -554,34 +566,20 @@ public void GenerateSchema_SupportsOption_UseAllOfForPolymorphism() }); var schemaRepository = new SchemaRepository(); - var schema = subject.GenerateSchema(typeof(BaseType), schemaRepository); + var schema = Assert.IsType(subject.GenerateSchema(typeof(BaseType), schemaRepository)); // The polymorphic schema Assert.NotNull(schema.OneOf); Assert.Equal(3, schema.OneOf.Count); // The base type schema - Assert.NotNull(schema.OneOf[0].Reference); - var baseSchema = schemaRepository.Schemas[schema.OneOf[0].Reference.Id]; - Assert.Equal(JsonSchemaTypes.Object, baseSchema.Type); - Assert.Equal(["BaseProperty"], baseSchema.Properties.Keys); + var baseSchema = Assert.IsType(schema.OneOf[0]); + Assert.Equal("BaseType", baseSchema.Reference.Id); // The first sub type schema - Assert.NotNull(schema.OneOf[1].Reference); - var subType1Schema = schemaRepository.Schemas[schema.OneOf[1].Reference.Id]; - Assert.Equal(JsonSchemaTypes.Object, subType1Schema.Type); - Assert.NotNull(subType1Schema.AllOf); - var allOf = Assert.Single(subType1Schema.AllOf); - Assert.NotNull(allOf.Reference); - Assert.Equal("BaseType", allOf.Reference.Id); - Assert.Equal(["Property1"], subType1Schema.Properties.Keys); + baseSchema = Assert.IsType(schema.OneOf[1]); + Assert.Equal("SubType1", baseSchema.Reference.Id); // The second sub type schema - Assert.NotNull(schema.OneOf[2].Reference); - var subType2Schema = schemaRepository.Schemas[schema.OneOf[2].Reference.Id]; - Assert.Equal(JsonSchemaTypes.Object, subType2Schema.Type); - Assert.NotNull(subType2Schema.AllOf); - allOf = Assert.Single(subType2Schema.AllOf); - Assert.NotNull(allOf.Reference); - Assert.Equal("BaseType", allOf.Reference.Id); - Assert.Equal(["Property2"], subType2Schema.Properties.Keys); + baseSchema = Assert.IsType(schema.OneOf[2]); + Assert.Equal("SubType2", baseSchema.Reference.Id); } [Fact] @@ -594,7 +592,7 @@ public void GenerateSchema_SupportsOption_UseAllOfToExtendReferenceSchemas() var schema = subject.GenerateSchema(propertyInfo.PropertyType, new SchemaRepository(), memberInfo: propertyInfo); - Assert.Null(schema.Reference); + Assert.IsNotType(schema); Assert.NotNull(schema.AllOf); Assert.Single(schema.AllOf); } @@ -617,11 +615,11 @@ public void GenerateSchema_HandlesTypesWithNestedTypes() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(ContainingType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(ContainingType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); - Assert.Equal("NestedType", schema.Properties["Property1"].Reference.Id); + Assert.Equal("NestedType", Assert.IsType(schema.Properties["Property1"]).Reference.Id); } [Fact] @@ -641,11 +639,11 @@ public void GenerateSchema_HandlesTypesWithOverriddenProperties() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(TypeWithOverriddenProperty), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(TypeWithOverriddenProperty), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); - Assert.Equal(JsonSchemaTypes.String, schema.Properties["Property1"].Type); + Assert.Equal(JsonSchemaTypes.String | JsonSchemaType.Null, schema.Properties["Property1"].Type); } [Fact] @@ -656,10 +654,10 @@ public void GenerateSchema_HandlesRecursion_IfCalledAgainWithinAFilter() ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(ComplexType), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(ComplexType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.Equal("ComplexType", schema.Properties["Self"].Reference.Id); + Assert.Equal("ComplexType", Assert.IsType(schema.Properties["Self"]).Reference.Id); } [Fact] @@ -693,7 +691,7 @@ public void GenerateSchema_HonorsSerializerSetting_StringEnumConverter( ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(TypeWithDefaultAttributeOnEnum), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(TypeWithDefaultAttributeOnEnum), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; var propertySchema = schema.Properties[nameof(TypeWithDefaultAttributeOnEnum.EnumWithDefault)]; @@ -732,7 +730,7 @@ public void GenerateSchema_HonorsSerializerSetting_TypeNameHandling( ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(BaseType), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(BaseType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; if (expectedDiscriminatorPresent) @@ -744,11 +742,11 @@ public void GenerateSchema_HonorsSerializerSetting_TypeNameHandling( Assert.Equal( expected: new Dictionary { - [string.Format(expectedDiscriminatorMappingKeyFormat, "BaseType")] = "#/components/schemas/BaseType", - [string.Format(expectedDiscriminatorMappingKeyFormat, "SubType1")] = "#/components/schemas/SubType1", - [string.Format(expectedDiscriminatorMappingKeyFormat, "SubType2")] = "#/components/schemas/SubType2" + [string.Format(expectedDiscriminatorMappingKeyFormat, "BaseType")] = "BaseType", + [string.Format(expectedDiscriminatorMappingKeyFormat, "SubType1")] = "SubType1", + [string.Format(expectedDiscriminatorMappingKeyFormat, "SubType2")] = "SubType2", }, - actual: schema.Discriminator.Mapping); + actual: schema.Discriminator.Mapping.ToDictionary((k) => k.Key, (v) => v.Value.Reference.Id)); } else { @@ -769,7 +767,7 @@ public void GenerateSchema_HonorsSerializeSetting_ContractResolver() ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(typeof(BaseType), schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(typeof(BaseType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; @@ -781,7 +779,7 @@ public void GenerateSchema_HonorsSerializerAttribute_StringEnumConverter() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(JsonConverterAnnotatedEnum), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(JsonConverterAnnotatedEnum), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(JsonSchemaTypes.String, schema.Type); @@ -793,7 +791,7 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonIgnore() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(JsonIgnoreAnnotatedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(JsonIgnoreAnnotatedType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(["StringWithNoAnnotation"], schema.Properties.Keys); @@ -804,9 +802,11 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonProperty() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(JsonPropertyAnnotatedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(JsonPropertyAnnotatedType), schemaRepository)); + + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal( [ "string-with-json-property-name", @@ -834,22 +834,19 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonProperty() ], schema.Required ); - Assert.True(schema.Properties["string-with-json-property-name"].Nullable); - Assert.False(schema.Properties["IntWithRequiredDefault"].Nullable); - Assert.True(schema.Properties["StringWithRequiredDefault"].Nullable); - Assert.False(schema.Properties["StringWithRequiredDisallowNull"].Nullable); - Assert.False(schema.Properties["StringWithRequiredAlways"].Nullable); - Assert.True(schema.Properties["StringWithRequiredAllowNull"].Nullable); - Assert.False(schema.Properties["StringWithRequiredAlwaysButConflictingDataMember"].Nullable); - Assert.True(schema.Properties["StringWithRequiredDefaultButConflictingDataMember"].Nullable); - Assert.False(schema.Properties["IntEnumWithRequiredDefault"].Nullable); - Assert.False(schema.Properties["IntEnumWithRequiredAllowNull"].Nullable); - Assert.False(schema.Properties["IntEnumWithRequiredAlways"].Nullable); - Assert.False(schema.Properties["IntEnumWithRequiredDisallowNull"].Nullable); - Assert.Equal("IntEnum", schema.Properties["IntEnumWithRequiredDefault"].Reference.Id); - Assert.Equal("IntEnum", schema.Properties["IntEnumWithRequiredAllowNull"].Reference.Id); - Assert.Equal(nameof(IntEnum), schema.Properties["IntEnumWithRequiredAlways"].Reference.Id); - Assert.Equal(nameof(IntEnum), schema.Properties["IntEnumWithRequiredDisallowNull"].Reference.Id); + + Assert.True(schema.Properties["string-with-json-property-name"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["IntWithRequiredDefault"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.True(schema.Properties["StringWithRequiredDefault"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["StringWithRequiredDisallowNull"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["StringWithRequiredAlways"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.True(schema.Properties["StringWithRequiredAllowNull"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["StringWithRequiredAlwaysButConflictingDataMember"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.True(schema.Properties["StringWithRequiredDefaultButConflictingDataMember"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["IntEnumWithRequiredDefault"].Type.HasValue); + Assert.False(schema.Properties["IntEnumWithRequiredAllowNull"].Type.HasValue); + Assert.False(schema.Properties["IntEnumWithRequiredAlways"].Type.HasValue); + Assert.False(schema.Properties["IntEnumWithRequiredDisallowNull"].Type.HasValue); } [Fact] @@ -857,13 +854,16 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonRequired() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(JsonRequiredAnnotatedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(JsonRequiredAnnotatedType), schemaRepository)); + + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal(["IntEnumWithRequired", "NullableIntEnumWithRequired", "StringWithConflictingRequired", "StringWithJsonRequired"], schema.Required); - Assert.False(schema.Properties["StringWithJsonRequired"].Nullable); - Assert.False(schema.Properties["IntEnumWithRequired"].Nullable); - Assert.Equal(nameof(IntEnum), schema.Properties["IntEnumWithRequired"].Reference.Id); + Assert.False(schema.Properties["StringWithJsonRequired"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["IntEnumWithRequired"].Type.HasValue); + reference = Assert.IsType(schema.Properties["IntEnumWithRequired"]); + Assert.Equal(nameof(IntEnum), reference.Reference.Id); Assert.True(schemaRepository.TryLookupByType(typeof(IntEnum), out _)); Assert.False(schemaRepository.TryLookupByType(typeof(IntEnum?), out _)); } @@ -873,7 +873,7 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonObject() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(JsonObjectAnnotatedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(JsonObjectAnnotatedType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.Equal( @@ -885,10 +885,10 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonObject() ], schema.Required ); - Assert.False(schema.Properties["StringWithNoAnnotation"].Nullable); - Assert.False(schema.Properties["StringWithRequiredUnspecified"].Nullable); - Assert.True(schema.Properties["StringWithRequiredAllowNull"].Nullable); - Assert.False(schema.Properties["StringWithDataMemberRequiredFalse"].Nullable); + Assert.False(schema.Properties["StringWithNoAnnotation"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["StringWithRequiredUnspecified"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.True(schema.Properties["StringWithRequiredAllowNull"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.False(schema.Properties["StringWithDataMemberRequiredFalse"].Type.Value.HasFlag(JsonSchemaType.Null)); } [Fact] @@ -896,7 +896,7 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonExtensionData() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(JsonExtensionDataAnnotatedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(JsonExtensionDataAnnotatedType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.True(schema.AdditionalPropertiesAllowed); @@ -909,7 +909,7 @@ public void GenerateSchema_HonorsAttribute_SwaggerIgnore() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(SwaggerIngoreAnnotatedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(SwaggerIngoreAnnotatedType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; @@ -925,15 +925,14 @@ public void GenerateSchema_HonorsDataMemberAttribute() { var schemaRepository = new SchemaRepository(); - var referenceSchema = Subject().GenerateSchema(typeof(DataMemberAnnotatedType), schemaRepository); + var referenceSchema = Assert.IsType(Subject().GenerateSchema(typeof(DataMemberAnnotatedType), schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - - Assert.True(schema.Properties["StringWithDataMemberRequired"].Nullable); - Assert.True(schema.Properties["StringWithDataMemberNonRequired"].Nullable); - Assert.True(schema.Properties["RequiredWithCustomNameFromDataMember"].Nullable); - Assert.True(schema.Properties["NonRequiredWithCustomNameFromDataMember"].Nullable); + Assert.True(schema.Properties["StringWithDataMemberRequired"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.True(schema.Properties["StringWithDataMemberNonRequired"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.True(schema.Properties["RequiredWithCustomNameFromDataMember"].Type.Value.HasFlag(JsonSchemaType.Null)); + Assert.True(schema.Properties["NonRequiredWithCustomNameFromDataMember"].Type.Value.HasFlag(JsonSchemaType.Null)); Assert.Equal( [ @@ -969,7 +968,7 @@ public void GenerateSchema_HonorsSerializerSetting_ProblemDetailsConverter(Type ); var schemaRepository = new SchemaRepository(); - var referenceSchema = subject.GenerateSchema(type, schemaRepository); + var referenceSchema = Assert.IsType(subject.GenerateSchema(type, schemaRepository)); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; Assert.DoesNotContain("Extensions", schema.Properties.Keys); @@ -985,9 +984,8 @@ public void GenerateSchema_HonorsSerializerSetting_ProblemDetailsConverter(Type [InlineData(typeof(JArray))] public void GenerateSchema_GeneratesOpenSchema_IfDynamicJsonType(Type type) { - var schema = Subject().GenerateSchema(type, new SchemaRepository()); + var schema = Assert.IsType(Subject().GenerateSchema(type, new SchemaRepository())); - Assert.Null(schema.Reference); Assert.Null(schema.Type); } diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Swashbuckle.AspNetCore.Newtonsoft.Test.csproj b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Swashbuckle.AspNetCore.Newtonsoft.Test.csproj index 2cece83730..935262b978 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Swashbuckle.AspNetCore.Newtonsoft.Test.csproj +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Swashbuckle.AspNetCore.Newtonsoft.Test.csproj @@ -6,6 +6,7 @@ + diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/RecursiveCallSchemaFilter.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/RecursiveCallSchemaFilter.cs index 14080c3790..f1999b228a 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/RecursiveCallSchemaFilter.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/RecursiveCallSchemaFilter.cs @@ -1,10 +1,10 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; public class RecursiveCallSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema model, SchemaFilterContext context) + public void Apply(IOpenApiSchema model, SchemaFilterContext context) { if (model.Type == JsonSchemaTypes.Object) { diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestDocumentFilter.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestDocumentFilter.cs index d5a212e935..24b455e342 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestDocumentFilter.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestDocumentFilter.cs @@ -1,5 +1,4 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.TestSupport; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -8,8 +7,9 @@ public class TestDocumentFilter : IDocumentFilter, IDocumentAsyncFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { - swaggerDoc.Extensions.Add("X-foo", new OpenApiString("bar")); - swaggerDoc.Extensions.Add("X-docName", new OpenApiString(context.DocumentName)); + swaggerDoc.Extensions ??= new Dictionary(); + swaggerDoc.Extensions.Add("X-foo", new JsonNodeExtension("bar")); + swaggerDoc.Extensions.Add("X-docName", new JsonNodeExtension(context.DocumentName)); context.SchemaGenerator.GenerateSchema(typeof(ComplexType), context.SchemaRepository); } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestEnumSchemaFilter.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestEnumSchemaFilter.cs index 0d791449e3..49a5246e80 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestEnumSchemaFilter.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestEnumSchemaFilter.cs @@ -1,11 +1,11 @@ using System.Text; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test.Fixtures; internal class TestEnumSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { bool isEnumArgument = (context.Type?.GenericTypeArguments?.Length ?? 0) == 1 && context.Type.GenericTypeArguments.All(b => b.IsEnum); var isEnumArray = context.Type.IsArray && context.Type.GetElementType().IsEnum; diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestOperationFilter.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestOperationFilter.cs index b3e13e2cb7..58c2536819 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestOperationFilter.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestOperationFilter.cs @@ -1,5 +1,4 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -7,8 +6,9 @@ public class TestOperationFilter : IOperationFilter, IOperationAsyncFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { - operation.Extensions.Add("X-foo", new OpenApiString("bar")); - operation.Extensions.Add("X-docName", new OpenApiString(context.DocumentName)); + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add("X-foo", new JsonNodeExtension("bar")); + operation.Extensions.Add("X-docName", new JsonNodeExtension(context.DocumentName)); } public Task ApplyAsync(OpenApiOperation operation, OperationFilterContext context, CancellationToken cancellationToken) diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestParameterFilter.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestParameterFilter.cs index 28caa151ee..ab3bfae958 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestParameterFilter.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestParameterFilter.cs @@ -1,17 +1,20 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; public class TestParameterFilter : IParameterFilter, IParameterAsyncFilter { - public void Apply(OpenApiParameter parameter, ParameterFilterContext context) + public void Apply(IOpenApiParameter parameter, ParameterFilterContext context) { - parameter.Extensions.Add("X-foo", new OpenApiString("bar")); - parameter.Extensions.Add("X-docName", new OpenApiString(context.DocumentName)); + if (parameter is OpenApiParameter openApiParameter) + { + openApiParameter.Extensions ??= new Dictionary(); + openApiParameter.Extensions.Add("X-foo", new JsonNodeExtension("bar")); + openApiParameter.Extensions.Add("X-docName", new JsonNodeExtension(context.DocumentName)); + } } - public Task ApplyAsync(OpenApiParameter parameter, ParameterFilterContext context, CancellationToken cancellationToken) + public Task ApplyAsync(IOpenApiParameter parameter, ParameterFilterContext context, CancellationToken cancellationToken) { Apply(parameter, context); return Task.CompletedTask; diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestRequestBodyFilter.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestRequestBodyFilter.cs index 0221466156..6ced63807d 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestRequestBodyFilter.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestRequestBodyFilter.cs @@ -1,17 +1,20 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; public class TestRequestBodyFilter : IRequestBodyFilter, IRequestBodyAsyncFilter { - public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context) + public void Apply(IOpenApiRequestBody requestBody, RequestBodyFilterContext context) { - requestBody.Extensions.Add("X-foo", new OpenApiString("bar")); - requestBody.Extensions.Add("X-docName", new OpenApiString(context.DocumentName)); + if (requestBody is OpenApiRequestBody body) + { + body.Extensions ??= new Dictionary(); + body.Extensions.Add("X-foo", new JsonNodeExtension("bar")); + body.Extensions.Add("X-docName", new JsonNodeExtension(context.DocumentName)); + } } - public Task ApplyAsync(OpenApiRequestBody requestBody, RequestBodyFilterContext context, CancellationToken cancellationToken) + public Task ApplyAsync(IOpenApiRequestBody requestBody, RequestBodyFilterContext context, CancellationToken cancellationToken) { Apply(requestBody, context); return Task.CompletedTask; diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestSchemaFilter.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestSchemaFilter.cs index 247c04a99b..dfde121e84 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestSchemaFilter.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Fixtures/TestSchemaFilter.cs @@ -1,13 +1,16 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; public class TestSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { - schema.Extensions.Add("X-foo", new OpenApiString("bar")); - schema.Extensions.Add("X-docName", new OpenApiString(context.DocumentName)); + if (schema is OpenApiSchema openApiSchema) + { + openApiSchema.Extensions ??= new Dictionary(); + openApiSchema.Extensions.Add("X-foo", new JsonNodeExtension("bar")); + openApiSchema.Extensions.Add("X-docName", new JsonNodeExtension(context.DocumentName)); + } } } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SchemaGenerator/JsonSerializerSchemaGeneratorTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SchemaGenerator/JsonSerializerSchemaGeneratorTests.cs index e5020c6fa3..f662064bf3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SchemaGenerator/JsonSerializerSchemaGeneratorTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SchemaGenerator/JsonSerializerSchemaGeneratorTests.cs @@ -11,13 +11,10 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Constraints; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen.Test.Fixtures; using Swashbuckle.AspNetCore.TestSupport; -using JsonSchemaType = string; - namespace Swashbuckle.AspNetCore.SwaggerGen.Test; public class JsonSerializerSchemaGeneratorTests @@ -60,16 +57,16 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type) { typeof(Version), JsonSchemaTypes.String, null }, { typeof(DateOnly), JsonSchemaTypes.String, "date" }, { typeof(TimeOnly), JsonSchemaTypes.String, "time" }, - { typeof(bool?), JsonSchemaTypes.Boolean, null }, - { typeof(int?), JsonSchemaTypes.Integer, "int32" }, - { typeof(DateTime?), JsonSchemaTypes.String, "date-time" }, - { typeof(Guid?), JsonSchemaTypes.String, "uuid" }, - { typeof(DateOnly?), JsonSchemaTypes.String, "date" }, - { typeof(TimeOnly?), JsonSchemaTypes.String, "time" }, + { typeof(bool?), JsonSchemaTypes.Boolean | JsonSchemaType.Null, null }, + { typeof(int?), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int32" }, + { typeof(DateTime?), JsonSchemaTypes.String | JsonSchemaType.Null, "date-time" }, + { typeof(Guid?), JsonSchemaTypes.String | JsonSchemaType.Null, "uuid" }, + { typeof(DateOnly?), JsonSchemaTypes.String | JsonSchemaType.Null, "date" }, + { typeof(TimeOnly?), JsonSchemaTypes.String | JsonSchemaType.Null, "time" }, { typeof(Int128), JsonSchemaTypes.Integer, "int128" }, - { typeof(Int128?), JsonSchemaTypes.Integer, "int128" }, + { typeof(Int128?), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int128" }, { typeof(UInt128), JsonSchemaTypes.Integer, "int128" }, - { typeof(UInt128?), JsonSchemaTypes.Integer, "int128" }, + { typeof(UInt128?), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int128" }, }; [Theory] @@ -86,41 +83,43 @@ public void GenerateSchema_GeneratesPrimitiveSchema_IfPrimitiveOrNullablePrimiti } [Theory] - [InlineData(typeof(IntEnum), "int32", false, "2", "4", "8")] - [InlineData(typeof(LongEnum), "int64", false, "2", "4", "8")] + [InlineData(typeof(IntEnum), JsonSchemaType.Integer, "int32", "2", "4", "8")] + [InlineData(typeof(LongEnum), JsonSchemaType.Integer, "int64", "2", "4", "8")] + [InlineData(typeof(IntEnum?), JsonSchemaType.Integer, "int32", "2", "4", "8")] + [InlineData(typeof(LongEnum?), JsonSchemaType.Integer, "int64", "2", "4", "8")] public void GenerateSchema_GeneratesReferencedEnumSchema_IfEnumOrNullableEnumType( Type type, + JsonSchemaType expectedType, string expectedFormat, - bool expectedNullable, params string[] expectedEnumAsJson) { var schemaRepository = new SchemaRepository(); var referenceSchema = Subject().GenerateSchema(type, schemaRepository); - Assert.NotNull(referenceSchema.Reference); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.Equal(JsonSchemaTypes.Integer, schema.Type); + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; + Assert.Equal(expectedType, schema.Type); Assert.Equal(expectedFormat, schema.Format); - Assert.Equal(expectedNullable, schema.Nullable); Assert.NotNull(schema.Enum); - Assert.Equal(expectedEnumAsJson, schema.Enum.Select(openApiAny => openApiAny.ToJson())); + Assert.Equal(expectedEnumAsJson, schema.Enum.Select(openApiAny => openApiAny?.ToJson()).ToArray()); } [Fact] - public void GenerateSchema_DedupsEnumValues_IfEnumTypeHasDuplicateValues() + public void GenerateSchema_DedupesEnumValues_IfEnumTypeHasDuplicateValues() { var enumType = typeof(HttpStatusCode); var schemaRepository = new SchemaRepository(); var referenceSchema = Subject().GenerateSchema(enumType, schemaRepository); - Assert.NotNull(referenceSchema.Reference); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(enumType.GetEnumValues().Cast().Distinct().Count(), schema.Enum.Count); } - public static TheoryData CollectionTypeData => new() +#nullable enable + public static TheoryData CollectionTypeData => new() { { typeof(IDictionary), JsonSchemaTypes.Integer }, { typeof(IDictionary), JsonSchemaTypes.Integer }, @@ -133,7 +132,7 @@ public void GenerateSchema_DedupsEnumValues_IfEnumTypeHasDuplicateValues() [MemberData(nameof(CollectionTypeData))] public void GenerateSchema_GeneratesDictionarySchema_IfDictionaryType( Type type, - JsonSchemaType expectedAdditionalPropertiesType) + JsonSchemaType? expectedAdditionalPropertiesType) { var schema = Subject().GenerateSchema(type, new SchemaRepository()); @@ -142,6 +141,7 @@ public void GenerateSchema_GeneratesDictionarySchema_IfDictionaryType( Assert.NotNull(schema.AdditionalProperties); Assert.Equal(expectedAdditionalPropertiesType, schema.AdditionalProperties.Type); } +#nullable restore [Fact] public void GenerateSchema_GeneratesReferencedDictionarySchema_IfDictionaryTypeIsSelfReferencing() @@ -150,34 +150,35 @@ public void GenerateSchema_GeneratesReferencedDictionarySchema_IfDictionaryTypeI var referenceSchema = Subject().GenerateSchema(typeof(DictionaryOfSelf), schemaRepository); - Assert.NotNull(referenceSchema.Reference); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); Assert.True(schema.AdditionalPropertiesAllowed); Assert.NotNull(schema.AdditionalProperties); - Assert.Equal(schema.AdditionalProperties.Reference.Id, referenceSchema.Reference.Id); // ref to self + var additionalReference = Assert.IsType(schema.AdditionalProperties); + Assert.Equal(additionalReference.Reference.Id, reference.Reference.Id); // ref to self } - public static TheoryData EnumerableTypeData => new() - { - { typeof(int[]), JsonSchemaTypes.Integer, "int32", false }, - { typeof(int?[]), JsonSchemaTypes.Integer, "int32", true }, - { typeof(double[]), JsonSchemaTypes.Number, "double", false }, - { typeof(double?[]), JsonSchemaTypes.Number, "double", true }, - { typeof(DateTime[]), JsonSchemaTypes.String, "date-time", false }, - { typeof(DateTime?[]), JsonSchemaTypes.String, "date-time", true }, - { typeof(IEnumerable), JsonSchemaTypes.String, null, false }, - { typeof(int[][]), JsonSchemaTypes.Array, null, false }, - { typeof(IList), null, null, false }, +#nullable enable + public static TheoryData EnumerableTypeData => new() + { + { typeof(int[]), JsonSchemaTypes.Integer, "int32" }, + { typeof(int?[]), JsonSchemaTypes.Integer | JsonSchemaType.Null, "int32" }, + { typeof(double[]), JsonSchemaTypes.Number, "double" }, + { typeof(double?[]), JsonSchemaTypes.Number | JsonSchemaType.Null, "double" }, + { typeof(DateTime[]), JsonSchemaTypes.String, "date-time" }, + { typeof(DateTime?[]), JsonSchemaTypes.String | JsonSchemaType.Null, "date-time" }, + { typeof(IEnumerable), JsonSchemaTypes.String, null }, + { typeof(int[][]), JsonSchemaTypes.Array, null }, + { typeof(IList), null, null }, }; [Theory] [MemberData(nameof(EnumerableTypeData))] public void GenerateSchema_GeneratesArraySchema_IfEnumerableType( Type type, - JsonSchemaType expectedItemsType, - string expectedItemsFormat, - bool expectedItemsNullable) + JsonSchemaType? expectedItemsType, + string? expectedItemsFormat) { var schema = Subject().GenerateSchema(type, new SchemaRepository()); @@ -185,8 +186,8 @@ public void GenerateSchema_GeneratesArraySchema_IfEnumerableType( Assert.NotNull(schema.Items); Assert.Equal(expectedItemsType, schema.Items.Type); Assert.Equal(expectedItemsFormat, schema.Items.Format); - Assert.Equal(expectedItemsNullable, schema.Items.Nullable); } +#nullable restore [Theory] [InlineData(typeof(ISet))] @@ -207,10 +208,11 @@ public void GenerateSchema_GeneratesReferencedArraySchema_IfEnumerableTypeIsSelf var referenceSchema = Subject().GenerateSchema(typeof(ListOfSelf), schemaRepository); - Assert.NotNull(referenceSchema.Reference); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Array, schema.Type); - Assert.Equal(schema.Items.Reference.Id, referenceSchema.Reference.Id); // ref to self + var itemsReference = Assert.IsType(schema.Items); + Assert.Equal(itemsReference.Reference.Id, reference.Reference.Id); // ref to self } [Theory] @@ -227,8 +229,8 @@ public void GenerateSchema_GeneratesReferencedObjectSchema_IfComplexType( var referenceSchema = Subject().GenerateSchema(type, schemaRepository); - Assert.NotNull(referenceSchema.Reference); - Assert.Equal(expectedSchemaId, referenceSchema.Reference.Id); + var reference = Assert.IsType(referenceSchema); + Assert.Equal(expectedSchemaId, reference.Reference.Id); var schema = schemaRepository.Schemas[expectedSchemaId]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); Assert.Equal(expectedProperties, schema.Properties.Keys); @@ -242,7 +244,8 @@ public void GenerateSchema_IncludesInheritedProperties_IfComplexTypeIsDerived() var referenceSchema = Subject().GenerateSchema(typeof(SubType1), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); Assert.Equal(["BaseProperty", "Property1"], schema.Properties.Keys); } @@ -260,7 +263,8 @@ public void GenerateSchema_IncludesInheritedProperties_IfTypeIsAnInterfaceHierar var referenceSchema = Subject().GenerateSchema(type, schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); Assert.Equal(expectedPropertyNames.OrderBy(n => n), schema.Properties.Keys.OrderBy(k => k)); } @@ -272,7 +276,8 @@ public void GenerateSchema_KeepMostDerivedType_IfTypeIsAnInterface() var referenceSchema = Subject().GenerateSchema(typeof(INewBaseInterface), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Integer, schema.Properties["BaseProperty"].Type); } @@ -283,7 +288,8 @@ public void GenerateSchema_ExcludesIndexerProperties_IfComplexTypeIsIndexed() var referenceSchema = Subject().GenerateSchema(typeof(IndexedType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); Assert.Equal(["Property1"], schema.Properties.Keys); } @@ -301,8 +307,9 @@ public void GenerateSchema_SetsNullableFlag_IfPropertyIsReferenceOrNullableType( var referenceSchema = Subject().GenerateSchema(declaringType, schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.Equal(expectedNullable, schema.Properties[propertyName].Nullable); + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; + Assert.Equal(expectedNullable, schema.Properties[propertyName].Type.Value.HasFlag(JsonSchemaType.Null)); } [Theory] @@ -315,7 +322,7 @@ public void GenerateSchema_SetsNullableFlag_IfPropertyIsReferenceOrNullableType( [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.StringWithDefault), "\"foobar\"")] [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.IntArrayWithDefault), "[\n 1,\n 2,\n 3\n]")] [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.StringArrayWithDefault), "[\n \"foo\",\n \"bar\"\n]")] - [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.NullableIntWithDefaultNullValue), "null")] + [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.NullableIntWithDefaultNullValue), null)] [InlineData(typeof(TypeWithDefaultAttributes), nameof(TypeWithDefaultAttributes.NullableIntWithDefaultValue), "2147483647")] public void GenerateSchema_SetsDefault_IfPropertyHasDefaultValueAttribute( Type declaringType, @@ -331,10 +338,10 @@ public void GenerateSchema_SetsDefault_IfPropertyHasDefaultValueAttribute( var referenceSchema = Subject().GenerateSchema(declaringType, schemaRepository); // Assert - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; var propertySchema = schema.Properties[propertyName]; - Assert.NotNull(propertySchema.Default); - Assert.Equal(expectedDefaultAsJson, propertySchema.Default.ToJson()); + Assert.Equal(expectedDefaultAsJson, propertySchema.Default?.ToJson()); } [Fact] @@ -344,7 +351,8 @@ public void GenerateSchema_SetsDeprecatedFlag_IfPropertyHasObsoleteAttribute() var referenceSchema = Subject().GenerateSchema(typeof(TypeWithObsoleteAttribute), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.True(schema.Properties["ObsoleteProperty"].Deprecated); } @@ -357,7 +365,8 @@ public void GenerateSchema_SetsValidationProperties_IfComplexTypeHasValidationAt var referenceSchema = Subject().GenerateSchema(type, schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal("credit-card", schema.Properties["StringWithDataTypeCreditCard"].Format); Assert.Equal(1, schema.Properties["StringWithMinMaxLength"].MinLength); Assert.Equal(3, schema.Properties["StringWithMinMaxLength"].MaxLength); @@ -367,20 +376,20 @@ public void GenerateSchema_SetsValidationProperties_IfComplexTypeHasValidationAt Assert.Equal(3, schema.Properties["StringWithLength"].MaxLength); Assert.Equal(1, schema.Properties["ArrayWithLength"].MinItems); Assert.Equal(3, schema.Properties["ArrayWithLength"].MaxItems); - Assert.Equal(true, schema.Properties["IntWithExclusiveRange"].ExclusiveMinimum); - Assert.Equal(true, schema.Properties["IntWithExclusiveRange"].ExclusiveMaximum); + Assert.NotNull(schema.Properties["IntWithExclusiveRange"].ExclusiveMinimum); + Assert.NotNull(schema.Properties["IntWithExclusiveRange"].ExclusiveMaximum); Assert.Equal("byte", schema.Properties["StringWithBase64"].Format); - Assert.Equal(JsonSchemaTypes.String, schema.Properties["StringWithBase64"].Type); + Assert.Equal(JsonSchemaTypes.String | JsonSchemaType.Null, schema.Properties["StringWithBase64"].Type); Assert.Null(schema.Properties["IntWithRange"].ExclusiveMinimum); Assert.Null(schema.Properties["IntWithRange"].ExclusiveMaximum); - Assert.Equal(1, schema.Properties["IntWithRange"].Minimum); - Assert.Equal(10, schema.Properties["IntWithRange"].Maximum); + Assert.Equal("1", schema.Properties["IntWithRange"].Minimum); + Assert.Equal("10", schema.Properties["IntWithRange"].Maximum); Assert.Equal("^[3-6]?\\d{12,15}$", schema.Properties["StringWithRegularExpression"].Pattern); Assert.Equal(5, schema.Properties["StringWithStringLength"].MinLength); Assert.Equal(10, schema.Properties["StringWithStringLength"].MaxLength); Assert.Equal(1, schema.Properties["StringWithRequired"].MinLength); - Assert.False(schema.Properties["StringWithRequired"].Nullable); - Assert.False(schema.Properties["StringWithRequiredAllowEmptyTrue"].Nullable); + AssertIsNullable(schema.Properties["StringWithRequired"], false); + AssertIsNullable(schema.Properties["StringWithRequiredAllowEmptyTrue"], false); Assert.Null(schema.Properties["StringWithRequiredAllowEmptyTrue"].MinLength); Assert.Equal(["NullableIntEnumWithRequired", "StringWithRequired", "StringWithRequiredAllowEmptyTrue"], schema.Required); Assert.Equal("Description", schema.Properties[nameof(TypeWithValidationAttributes.StringWithDescription)].Description); @@ -394,7 +403,8 @@ public void GenerateSchema_SetsReadOnlyAndWriteOnlyFlags_IfPropertyIsRestricted( var referenceSchema = Subject().GenerateSchema(typeof(TypeWithRestrictedProperties), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.False(schema.Properties["ReadWriteProperty"].ReadOnly); Assert.False(schema.Properties["ReadWriteProperty"].WriteOnly); Assert.True(schema.Properties["ReadOnlyProperty"].ReadOnly); @@ -422,10 +432,11 @@ public void GenerateSchema_SetsRequired_IfPropertyHasRequiredKeyword() var referenceSchema = Subject().GenerateSchema(typeof(TypeWithRequiredProperties), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.True(schema.Properties["RequiredString"].Nullable); + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; + AssertIsNullable(schema.Properties["RequiredString"]); Assert.Contains("RequiredString", schema.Required.ToArray()); - Assert.False(schema.Properties["RequiredInt"].Nullable); + AssertIsNullable(schema.Properties["RequiredInt"], false); Assert.Contains("RequiredInt", schema.Required.ToArray()); } @@ -436,9 +447,10 @@ public void GenerateSchema_SetsRequired_IfPropertyHasRequiredKeywordAndValidatio var referenceSchema = Subject().GenerateSchema(typeof(TypeWithRequiredPropertyAndValidationAttribute), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(1, schema.Properties["RequiredProperty"].MinLength); - Assert.True(schema.Properties["RequiredProperty"].Nullable); + AssertIsNullable(schema.Properties["RequiredProperty"]); Assert.Equal(["RequiredProperty"], schema.Required); } @@ -456,10 +468,18 @@ public void GenerateSchema_SetsRequiredAndNullable_IfPropertyHasRequiredKeywordA var referenceSchema = Subject(configureGenerator: (c) => c.SupportNonNullableReferenceTypes = true).GenerateSchema(typeof(TypeWithNullableReferenceTypes), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.True(schema.Properties["RequiredNullableString"].Nullable); + var reference = Assert.IsType(referenceSchema); + + Assert.NotNull(reference); + Assert.NotNull(reference.Reference); + Assert.NotNull(reference.Reference.Id); + + var schema = schemaRepository.Schemas[reference.Reference.Id]; + Assert.NotNull(schema.Properties); + AssertIsNullable(schema.Properties["RequiredNullableString"]); + Assert.NotNull(schema.Required); Assert.Contains("RequiredNullableString", schema.Required.ToArray()); - Assert.False(schema.Properties["RequiredNonNullableString"].Nullable); + AssertIsNullable(schema.Properties["RequiredNonNullableString"], false); Assert.Contains("RequiredNonNullableString", schema.Required.ToArray()); } #nullable disable @@ -478,7 +498,8 @@ bool expectedReadOnly var referenceSchema = Subject().GenerateSchema(type, schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(expectedReadOnly, schema.Properties[propertyName].ReadOnly); } @@ -512,7 +533,7 @@ public void GenerateSchema_SupportsOption_CustomTypeMappings( var schema = subject.GenerateSchema(type, new SchemaRepository()); Assert.Equal(JsonSchemaTypes.String, schema.Type); - Assert.Empty(schema.Properties); + Assert.Null(schema.Properties); } [Theory] @@ -529,10 +550,14 @@ public void GenerateSchema_SupportsOption_SchemaFilters(Type type) var schema = subject.GenerateSchema(type, schemaRepository); - var definitionSchema = schema.Reference == null ? schema : schemaRepository.Schemas[schema.Reference.Id]; - Assert.Contains("X-foo", definitionSchema.Extensions.Keys); + if (schema is OpenApiSchemaReference reference) + { + schema = schemaRepository.Schemas[reference.Reference.Id]; + } + + Assert.Contains("X-foo", schema.Extensions.Keys); - Assert.Equal("v1", ((OpenApiString)definitionSchema.Extensions["X-docName"]).Value); + Assert.Equal("v1", ((JsonNodeExtension)schema.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -545,7 +570,8 @@ public void GenerateSchema_SupportsOption_IgnoreObsoleteProperties() var referenceSchema = subject.GenerateSchema(typeof(TypeWithObsoleteAttribute), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.DoesNotContain("ObsoleteProperty", schema.Properties.Keys); } @@ -559,8 +585,9 @@ public void GenerateSchema_SupportsOption_SchemaIdSelector() var referenceSchema = subject.GenerateSchema(typeof(ComplexType), schemaRepository); - Assert.Equal("Swashbuckle.AspNetCore.TestSupport.ComplexType", referenceSchema.Reference.Id); - Assert.Contains(referenceSchema.Reference.Id, schemaRepository.Schemas.Keys); + var reference = Assert.IsType(referenceSchema); + Assert.Equal("Swashbuckle.AspNetCore.TestSupport.ComplexType", reference.Reference.Id); + Assert.Contains(reference.Reference.Id, schemaRepository.Schemas.Keys); } [Fact] @@ -573,16 +600,17 @@ public void GenerateSchema_SupportsOption_UseAllOfForInheritance() var referenceSchema = subject.GenerateSchema(typeof(SubType1), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.NotNull(schema.AllOf); Assert.Equal(2, schema.AllOf.Count); var baseSchema = schema.AllOf[0]; - Assert.Equal("BaseType", baseSchema.Reference.Id); - Assert.NotNull(baseSchema.Reference); + reference = Assert.IsType(baseSchema); + Assert.Equal("BaseType", reference.Reference.Id); var subSchema = schema.AllOf[1]; Assert.Equal(["Property1"], subSchema.Properties.Keys); // The base type schema - var baseTypeSchema = schemaRepository.Schemas[baseSchema.Reference.Id]; + var baseTypeSchema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, baseTypeSchema.Type); Assert.Equal(["BaseProperty"], baseTypeSchema.Properties.Keys); } @@ -639,7 +667,8 @@ public void GenerateSchema_SupportsOption_DiscriminatorNameSelector() var referenceSchema = subject.GenerateSchema(typeof(BaseType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Contains("TypeName", schema.Properties.Keys); Assert.Contains("TypeName", schema.Required); Assert.NotNull(schema.Discriminator); @@ -660,28 +689,31 @@ public void GenerateSchema_SupportsOption_UseAllOfForPolymorphism() // The polymorphic schema Assert.NotNull(schema.OneOf); Assert.Equal(3, schema.OneOf.Count); + // The base type schema - Assert.NotNull(schema.OneOf[0].Reference); - var baseSchema = schemaRepository.Schemas[schema.OneOf[0].Reference.Id]; + var reference = Assert.IsType(schema.OneOf[0]); + var baseSchema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, baseSchema.Type); Assert.Equal(["BaseProperty"], baseSchema.Properties.Keys); + // The first sub type schema - Assert.NotNull(schema.OneOf[1].Reference); - var subType1Schema = schemaRepository.Schemas[schema.OneOf[1].Reference.Id]; + reference = Assert.IsType(schema.OneOf[1]); + var subType1Schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, subType1Schema.Type); Assert.NotNull(subType1Schema.AllOf); var allOf = Assert.Single(subType1Schema.AllOf); - Assert.NotNull(allOf.Reference); - Assert.Equal("BaseType", allOf.Reference.Id); + reference = Assert.IsType(allOf); + Assert.Equal("BaseType", reference.Reference.Id); Assert.Equal(["Property1"], subType1Schema.Properties.Keys); + // The second sub type schema - Assert.NotNull(schema.OneOf[2].Reference); - var subType2Schema = schemaRepository.Schemas[schema.OneOf[2].Reference.Id]; + reference = Assert.IsType(schema.OneOf[2]); + var subType2Schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, subType2Schema.Type); Assert.NotNull(subType2Schema.AllOf); allOf = Assert.Single(subType2Schema.AllOf); - Assert.NotNull(allOf.Reference); - Assert.Equal("BaseType", allOf.Reference.Id); + reference = Assert.IsType(allOf); + Assert.Equal("BaseType", reference.Reference.Id); Assert.Equal(["Property2"], subType2Schema.Properties.Keys); } @@ -695,7 +727,7 @@ public void GenerateSchema_SupportsOption_UseAllOfToExtendReferenceSchemas() var schema = subject.GenerateSchema(propertyInfo.PropertyType, new SchemaRepository(), memberInfo: propertyInfo); - Assert.Null(schema.Reference); + Assert.IsNotType(schema); Assert.NotNull(schema.AllOf); Assert.Single(schema.AllOf); } @@ -784,8 +816,9 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes( var referenceSchema = subject.GenerateSchema(declaringType, schemaRepository); - var propertySchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName]; - Assert.Equal(expectedNullable, propertySchema.Nullable); + var reference = Assert.IsType(referenceSchema); + var propertySchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName]; + AssertIsNullable(propertySchema, expectedNullable); } [Theory] @@ -810,10 +843,11 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes_Nulla var referenceSchema = subject.GenerateSchema(declaringType, schemaRepository); - var propertySchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName]; - var contentSchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName].AdditionalProperties; - Assert.Equal(expectedNullableProperty, propertySchema.Nullable); - Assert.Equal(expectedNullableContent, contentSchema.Nullable); + var reference = Assert.IsType(referenceSchema); + var propertySchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName]; + var contentSchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName].AdditionalProperties; + AssertIsNullable(propertySchema, expectedNullableProperty); + AssertIsNullable(contentSchema, expectedNullableContent); } [Theory] @@ -838,10 +872,11 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes_Nulla var referenceSchema = subject.GenerateSchema(declaringType, schemaRepository); - var propertySchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName]; - var contentSchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName].AdditionalProperties; - Assert.Equal(expectedNullableProperty, propertySchema.Nullable); - Assert.Equal(expectedNullableContent, contentSchema.Nullable); + var reference = Assert.IsType(referenceSchema); + var propertySchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName]; + var contentSchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName].AdditionalProperties; + AssertIsNullable(propertySchema, expectedNullableProperty); + AssertIsNullable(contentSchema, expectedNullableContent); } [Theory] @@ -866,10 +901,11 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes_Nulla var referenceSchema = subject.GenerateSchema(declaringType, schemaRepository); - var propertySchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName]; - var contentSchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName].AdditionalProperties; - Assert.Equal(expectedNullableProperty, propertySchema.Nullable); - Assert.Equal(expectedNullableContent, contentSchema.Nullable); + var reference = Assert.IsType(referenceSchema); + var propertySchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName]; + var contentSchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName].AdditionalProperties; + AssertIsNullable(propertySchema, expectedNullableProperty); + AssertIsNullable(contentSchema, expectedNullableContent); } [Theory] @@ -894,10 +930,11 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes_Nulla var referenceSchema = subject.GenerateSchema(declaringType, schemaRepository); - var propertySchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName]; - var contentSchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName].AdditionalProperties; - Assert.Equal(expectedNullableProperty, propertySchema.Nullable); - Assert.Equal(expectedNullableContent, contentSchema.Nullable); + var reference = Assert.IsType(referenceSchema); + var propertySchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName]; + var contentSchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName].AdditionalProperties; + AssertIsNullable(propertySchema, expectedNullableProperty); + AssertIsNullable(contentSchema, expectedNullableContent); } [Theory] @@ -922,10 +959,11 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes_Nulla var referenceSchema = subject.GenerateSchema(declaringType, schemaRepository); - var propertySchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName]; - var contentSchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName].AdditionalProperties; - Assert.Equal(expectedNullableProperty, propertySchema.Nullable); - Assert.Equal(expectedNullableContent, contentSchema.Nullable); + var reference = Assert.IsType(referenceSchema); + var propertySchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName]; + var contentSchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName].AdditionalProperties; + AssertIsNullable(propertySchema, expectedNullableProperty); + AssertIsNullable(contentSchema, expectedNullableContent); } [Theory] @@ -950,10 +988,11 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes_Nulla var referenceSchema = subject.GenerateSchema(declaringType, schemaRepository); - var propertySchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName]; - var contentSchema = schemaRepository.Schemas[referenceSchema.Reference.Id].Properties[propertyName].AdditionalProperties; - Assert.Equal(expectedNullableProperty, propertySchema.Nullable); - Assert.Equal(expectedNullableContent, contentSchema.Nullable); + var reference = Assert.IsType(referenceSchema); + var propertySchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName]; + var contentSchema = schemaRepository.Schemas[reference.Reference.Id].Properties[propertyName].AdditionalProperties; + AssertIsNullable(propertySchema, expectedNullableProperty); + AssertIsNullable(contentSchema, expectedNullableContent); } [Theory] @@ -975,7 +1014,7 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypesInDict subject.GenerateSchema(declaringType, schemaRepository); var propertySchema = schemaRepository.Schemas[subType].Properties[propertyName]; - Assert.Equal(expectedNullable, propertySchema.Nullable); + AssertIsNullable(propertySchema, expectedNullable); } [Theory] @@ -1036,7 +1075,7 @@ public void GenerateSchema_SupportsOption_SupportNonNullableReferenceTypes_Neste subject.GenerateSchema(declaringType, schemaRepository); var propertySchema = schemaRepository.Schemas[subType].Properties[propertyName]; - Assert.Equal(expectedNullable, propertySchema.Nullable); + AssertIsNullable(propertySchema, expectedNullable); } [Theory] @@ -1069,9 +1108,11 @@ public void GenerateSchema_HandlesTypesWithNestedTypes() var referenceSchema = Subject().GenerateSchema(typeof(ContainingType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.Object, schema.Type); - Assert.Equal("NestedType", schema.Properties["Property1"].Reference.Id); + reference = Assert.IsType(schema.Properties["Property1"]); + Assert.Equal("NestedType", reference.Reference.Id); } [Fact] @@ -1096,8 +1137,10 @@ public void GenerateSchema_HandlesRecursion_IfCalledAgainWithinAFilter() var referenceSchema = subject.GenerateSchema(typeof(ComplexType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.Equal("ComplexType", schema.Properties["Self"].Reference.Id); + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; + reference = Assert.IsType(schema.Properties["Self"]); + Assert.Equal("ComplexType", reference.Reference.Id); } [Fact] @@ -1124,8 +1167,8 @@ public void GenerateSchema_HonorsSerializerOption_IgnoreReadonlyProperties() var referenceSchema = subject.GenerateSchema(typeof(ComplexType), schemaRepository); - Assert.NotNull(referenceSchema.Reference); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; } [Fact] @@ -1139,8 +1182,8 @@ public void GenerateSchema_HonorsSerializerOption_PropertyNamingPolicy() var referenceSchema = subject.GenerateSchema(typeof(ComplexType), schemaRepository); - Assert.NotNull(referenceSchema.Reference); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(["property1", "property2"], schema.Properties.Keys); } @@ -1160,7 +1203,8 @@ public void GenerateSchema_HonorsSerializerOption_StringEnumConverter( var referenceSchema = subject.GenerateSchema(typeof(TypeWithDefaultAttributeOnEnum), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; var propertySchema = schema.Properties[nameof(TypeWithDefaultAttributeOnEnum.EnumWithDefault)]; Assert.Equal(JsonSchemaTypes.String, propertySchema.Type); Assert.Equal(expectedEnumAsJson, propertySchema.Enum.Select(openApiAny => openApiAny.ToJson())); @@ -1185,7 +1229,8 @@ public void GenerateSchema_HonorsSerializerAttribute_StringEnumConverter() var referenceSchema = Subject().GenerateSchema(typeof(JsonConverterAnnotatedEnum), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(JsonSchemaTypes.String, schema.Type); Assert.Equal(["\"Value1\"", "\"Value2\"", "\"X\""], schema.Enum.Select(openApiAny => openApiAny.ToJson())); } @@ -1197,7 +1242,8 @@ public void GenerateSchema_HonorsSerializerAttributes_JsonIgnore() var referenceSchema = Subject().GenerateSchema(typeof(JsonIgnoreAnnotatedType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; string[] expectedKeys = [ @@ -1217,7 +1263,8 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonPropertyName() var referenceSchema = Subject().GenerateSchema(typeof(JsonPropertyNameAnnotatedType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(["string-with-json-property-name"], schema.Properties.Keys); } @@ -1228,9 +1275,10 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonRequired() var referenceSchema = Subject().GenerateSchema(typeof(JsonRequiredAnnotatedType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.Equal(["StringWithJsonRequired"], schema.Required); - Assert.True(schema.Properties["StringWithJsonRequired"].Nullable); + AssertIsNullable(schema.Properties["StringWithJsonRequired"]); } [Fact] @@ -1240,7 +1288,8 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonExtensionData() var referenceSchema = Subject().GenerateSchema(typeof(JsonExtensionDataAnnotatedType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.True(schema.AdditionalPropertiesAllowed); Assert.NotNull(schema.AdditionalProperties); Assert.Null(schema.AdditionalProperties.Type); @@ -1253,7 +1302,8 @@ public void GenerateSchema_HonorsAttribute_SwaggerIgnore() var referenceSchema = Subject().GenerateSchema(typeof(SwaggerIngoreAnnotatedType), schemaRepository); - var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var reference = Assert.IsType(referenceSchema); + var schema = schemaRepository.Schemas[reference.Reference.Id]; Assert.True(schema.Properties.ContainsKey(nameof(SwaggerIngoreAnnotatedType.NotIgnoredString))); Assert.False(schema.Properties.ContainsKey(nameof(SwaggerIngoreAnnotatedType.IgnoredString))); @@ -1270,7 +1320,7 @@ public void GenerateSchema_GeneratesOpenSchema_IfDynamicJsonType(Type type) { var schema = Subject().GenerateSchema(type, new SchemaRepository()); - Assert.Null(schema.Reference); + Assert.IsNotType(schema); Assert.Null(schema.Type); } @@ -1349,13 +1399,9 @@ private static SchemaGenerator Subject( return new SchemaGenerator(generatorOptions, new JsonSerializerDataContractResolver(serializerOptions)); } - private static SchemaGenerator Subject(Action configureGenerator) + private static void AssertIsNullable(IOpenApiSchema schema, bool expected = true) { - var generatorOptions = new SchemaGeneratorOptions(); - configureGenerator?.Invoke(generatorOptions); - - var serializerOptions = new JsonSerializerOptions(); - - return new SchemaGenerator(generatorOptions, new JsonSerializerDataContractResolver(serializerOptions)); + Assert.True(schema.Type.HasValue); + Assert.Equal(expected, schema.Type.Value.HasFlag(JsonSchemaType.Null)); } } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/OpenApiAnyFactoryTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/OpenApiAnyFactoryTests.cs deleted file mode 100644 index 983e881882..0000000000 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/OpenApiAnyFactoryTests.cs +++ /dev/null @@ -1,141 +0,0 @@ -namespace Swashbuckle.AspNetCore.SwaggerGen.Test; - -using System; -using System.Text.Json; -using Microsoft.OpenApi.Any; -using Xunit; - -public class OpenApiAnyFactoryTests -{ - [Theory] - [InlineData("1", typeof(OpenApiInteger), 1)] - [InlineData("4294877294", typeof(OpenApiLong), 4294877294L)] - [InlineData("1.5", typeof(OpenApiFloat), 1.5f)] - [InlineData("1.5e308", typeof(OpenApiDouble), 1.5e308)] - [InlineData("\"abc\"", typeof(OpenApiString), "abc")] - [InlineData("true", typeof(OpenApiBoolean), true)] - [InlineData("false", typeof(OpenApiBoolean), false)] - public void CreateFromJson_SimpleType(string json, Type expectedType, object expectedValue) - { - var openApiAnyObject = OpenApiAnyFactory.CreateFromJson(json); - Assert.NotNull(openApiAnyObject); - Assert.Equal(expectedType, openApiAnyObject.GetType()); - Assert.Equal(AnyType.Primitive, openApiAnyObject.AnyType); - var valueProperty = expectedType.GetProperty("Value"); - var actualValue = valueProperty.GetValue(openApiAnyObject); - Assert.Equal(expectedValue, actualValue); - } - - [Fact] - public void CreateFromJson_NullType() - { - var expectedType = typeof(OpenApiNull); - - var openApiAnyObject = OpenApiAnyFactory.CreateFromJson("null"); - Assert.NotNull(openApiAnyObject); - Assert.Equal(expectedType, openApiAnyObject.GetType()); - Assert.Equal(AnyType.Null, openApiAnyObject.AnyType); - var valueProperty = expectedType.GetProperty("Value"); - Assert.Null(valueProperty); - } - - [Theory] - [InlineData("[1,2]", typeof(OpenApiInteger), 1, 2)] - [InlineData("[4294877294,4294877295]", typeof(OpenApiLong), 4294877294L, 4294877295L)] - [InlineData("[1.5,-1.5]", typeof(OpenApiFloat), 1.5f, -1.5f)] - [InlineData("[1.5e308,-1.5e308]", typeof(OpenApiDouble), 1.5e308, -1.5e308)] - [InlineData("[\"abc\",\"def\"]", typeof(OpenApiString), "abc", "def")] - [InlineData("[true,false]", typeof(OpenApiBoolean), true, false)] - [InlineData("[{\"a\":1,\"b\":2},{\"a\":3,\"b\":4}]", typeof(OpenApiObject))] - [InlineData("[[1,2],[3,4]]", typeof(OpenApiArray))] - public void CreateFromJson_Array(string json, Type expectedType, params object[] expectedValues) - { - var openApiAnyObject = OpenApiAnyFactory.CreateFromJson(json); - Assert.NotNull(openApiAnyObject); - Assert.Equal(typeof(OpenApiArray), openApiAnyObject.GetType()); - Assert.Equal(AnyType.Array, openApiAnyObject.AnyType); - var array = (OpenApiArray)openApiAnyObject; - for (var i = 0; i < array.Count; i++) - { - Assert.NotNull(array[i]); - Assert.Equal(expectedType, array[i].GetType()); - if (expectedValues.Length > 0) - { - var valueProperty = expectedType.GetProperty("Value"); - var expectedValue = expectedValues[i]; - var actualValue = valueProperty.GetValue(array[i]); - Assert.Equal(expectedValue, actualValue); - } - } - } - - [Fact] - public void CreateFromJson_Object() - { - var json = JsonSerializer.Serialize(new - { - int_value = 1, - long_value = 4294877294L, - float_value = 1.5f, - double_value = 1.5e308, - string_value = "abc", - true_value = true, - false_value = false, - array_value = new[] {1,2}, - object_value = new - { - a = 1, - b = 2 - } - }); - - var openApiAnyObject = OpenApiAnyFactory.CreateFromJson(json); - Assert.NotNull(openApiAnyObject); - Assert.Equal(typeof(OpenApiObject), openApiAnyObject.GetType()); - Assert.Equal(AnyType.Object, openApiAnyObject.AnyType); - var obj = (OpenApiObject)openApiAnyObject; - - Assert.NotNull(obj["int_value"]); - Assert.Equal(typeof(OpenApiInteger), obj["int_value"].GetType()); - Assert.Equal(AnyType.Primitive, obj["int_value"].AnyType); - Assert.Equal(1, ((OpenApiInteger) obj["int_value"]).Value); - - Assert.NotNull(obj["long_value"]); - Assert.Equal(typeof(OpenApiLong), obj["long_value"].GetType()); - Assert.Equal(AnyType.Primitive, obj["long_value"].AnyType); - Assert.Equal(4294877294L, ((OpenApiLong)obj["long_value"]).Value); - - Assert.NotNull(obj["float_value"]); - Assert.Equal(typeof(OpenApiFloat), obj["float_value"].GetType()); - Assert.Equal(AnyType.Primitive, obj["float_value"].AnyType); - Assert.Equal(1.5f, ((OpenApiFloat)obj["float_value"]).Value); - - Assert.NotNull(obj["double_value"]); - Assert.Equal(typeof(OpenApiDouble), obj["double_value"].GetType()); - Assert.Equal(AnyType.Primitive, obj["double_value"].AnyType); - Assert.Equal(1.5e308, ((OpenApiDouble)obj["double_value"]).Value); - - Assert.NotNull(obj["string_value"]); - Assert.Equal(typeof(OpenApiString), obj["string_value"].GetType()); - Assert.Equal(AnyType.Primitive, obj["string_value"].AnyType); - Assert.Equal("abc", ((OpenApiString)obj["string_value"]).Value); - - Assert.NotNull(obj["true_value"]); - Assert.Equal(typeof(OpenApiBoolean), obj["true_value"].GetType()); - Assert.Equal(AnyType.Primitive, obj["true_value"].AnyType); - Assert.True(((OpenApiBoolean)obj["true_value"]).Value); - - Assert.NotNull(obj["false_value"]); - Assert.Equal(typeof(OpenApiBoolean), obj["false_value"].GetType()); - Assert.Equal(AnyType.Primitive, obj["false_value"].AnyType); - Assert.False(((OpenApiBoolean)obj["false_value"]).Value); - - Assert.NotNull(obj["array_value"]); - Assert.Equal(typeof(OpenApiArray), obj["array_value"].GetType()); - Assert.Equal(AnyType.Array, obj["array_value"].AnyType); - - Assert.NotNull(obj["object_value"]); - Assert.Equal(typeof(OpenApiObject), obj["object_value"].GetType()); - Assert.Equal(AnyType.Object, obj["object_value"].AnyType); - } -} diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/OpenApiSchemaExtensionsTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/OpenApiSchemaExtensionsTests.cs index e75b8f65df..f01aab9e26 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/OpenApiSchemaExtensionsTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/OpenApiSchemaExtensionsTests.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.Globalization; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -92,9 +92,6 @@ public static void ApplyValidationAttributes_Handles_RangeAttribute_Correctly( string expectedMaximum) { // Arrange - var minimum = decimal.Parse(expectedMinimum, CultureInfo.InvariantCulture); - var maximum = decimal.Parse(expectedMaximum, CultureInfo.InvariantCulture); - var schema = new OpenApiSchema(); // Act @@ -104,10 +101,20 @@ public static void ApplyValidationAttributes_Handles_RangeAttribute_Correctly( } // Assert - Assert.Equal(isExclusive ? true : null, schema.ExclusiveMinimum); - Assert.Equal(isExclusive ? true : null, schema.ExclusiveMaximum); - Assert.Equal(minimum, schema.Minimum); - Assert.Equal(maximum, schema.Maximum); + if (isExclusive) + { + Assert.Equal(expectedMinimum, schema.ExclusiveMinimum); + Assert.Equal(expectedMaximum, schema.ExclusiveMaximum); + Assert.Null(schema.Minimum); + Assert.Null(schema.Maximum); + } + else + { + Assert.Equal(expectedMinimum, schema.Minimum); + Assert.Equal(expectedMaximum, schema.Maximum); + Assert.Null(schema.ExclusiveMinimum); + Assert.Null(schema.ExclusiveMaximum); + } } [Fact] diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs index ccde891856..a48e8afa91 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/SwaggerGenerator/SwaggerGeneratorTests.cs @@ -9,8 +9,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.AspNetCore.Routing; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen.Test.Fixtures; using Swashbuckle.AspNetCore.TestSupport; @@ -53,14 +52,14 @@ public void GetSwagger_GeneratesSwaggerDocument_ForApiDescriptionsWithMatchingGr Assert.Equal("V1", document.Info.Version); Assert.Equal("Test API", document.Info.Title); Assert.Equal(["/resource"], [.. document.Paths.Keys]); - Assert.Equal([OperationType.Post, OperationType.Get], document.Paths["/resource"].Operations.Keys); + Assert.Equal([HttpMethod.Post, HttpMethod.Get], document.Paths["/resource"].Operations.Keys); Assert.Equal(2, document.Paths["/resource"].Operations.Count); var documentV2 = subject.GetSwagger("v2"); Assert.Equal("V2", documentV2.Info.Version); Assert.Equal("Test API 2", documentV2.Info.Title); Assert.Equal(["/resource"], [.. documentV2.Paths.Keys]); - Assert.Equal([OperationType.Post], documentV2.Paths["/resource"].Operations.Keys); + Assert.Equal([HttpMethod.Post], documentV2.Paths["/resource"].Operations.Keys); Assert.Single(documentV2.Paths["/resource"].Operations); } @@ -113,7 +112,7 @@ public void GetSwagger_SetsOperationIdToNull_ByDefault() var document = subject.GetSwagger("v1"); - Assert.Null(document.Paths["/resource"].Operations[OperationType.Post].OperationId); + Assert.Null(document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); } [Fact] @@ -129,7 +128,7 @@ public void GetSwagger_SetsOperationIdToRouteName_IfActionHasRouteNameMetadata() var document = subject.GetSwagger("v1"); - Assert.Equal("SomeRouteName", document.Paths["/resource"].Operations[OperationType.Post].OperationId); + Assert.Equal("SomeRouteName", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); } [Fact] @@ -153,7 +152,7 @@ public void GetSwagger_SetsOperationIdToEndpointName_IfActionHasEndpointNameMeta var document = subject.GetSwagger("v1"); - Assert.Equal("SomeEndpointName", document.Paths["/resource"].Operations[OperationType.Post].OperationId); + Assert.Equal("SomeEndpointName", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); } [Fact] @@ -190,8 +189,8 @@ public void GetSwagger_UseProvidedOpenApiOperation_IfExistsInMetadata() var document = subject.GetSwagger("v1"); - Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[OperationType.Post].OperationId); - Assert.Equal("ParameterInMetadata", document.Paths["/resource"].Operations[OperationType.Post].Parameters[0].Name); + Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); + Assert.Equal("ParameterInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].Parameters[0].Name); } [Fact] @@ -244,12 +243,12 @@ public void GetSwagger_GenerateProducesSchemas_ForProvidedOpenApiOperation() var document = subject.GetSwagger("v1"); - Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[OperationType.Post].OperationId); - var content = Assert.Single(document.Paths["/resource"].Operations[OperationType.Post].Responses["200"].Content); + Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); + var content = Assert.Single(document.Paths["/resource"].Operations[HttpMethod.Post].Responses["200"].Content); Assert.Equal("application/someMediaType", content.Key); Assert.Null(content.Value.Schema.Type); - Assert.NotNull(content.Value.Schema.Reference); - Assert.Equal("TestDto", content.Value.Schema.Reference.Id); + var reference = Assert.IsType(content.Value.Schema); + Assert.Equal("TestDto", reference.Reference.Id); } [Fact] @@ -324,24 +323,24 @@ public void GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationAndApp var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal("OperationIdSetInMetadata", operation.OperationId); var content = Assert.Single(operation.RequestBody.Content); Assert.Equal("application/someMediaType", content.Key); Assert.Null(content.Value.Schema.Type); - Assert.NotNull(content.Value.Schema.Reference); - Assert.Equal("TestDto", content.Value.Schema.Reference.Id); + var reference = Assert.IsType(content.Value.Schema); + Assert.Equal("TestDto", reference.Reference.Id); 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); + Assert.Equal("bar", ((JsonNodeExtension)operation.RequestBody.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.RequestBody.Extensions["X-docName"]).Node.GetValue()); Assert.NotEmpty(operation.Parameters); Assert.Equal("paramQuery", operation.Parameters[0].Name); 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); + Assert.Equal("bar", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -392,10 +391,10 @@ public void GetSwagger_GenerateParametersSchemas_ForProvidedOpenApiOperation() var document = subject.GetSwagger("v1"); - Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[OperationType.Post].OperationId); - Assert.Equal("ParameterInMetadata", document.Paths["/resource"].Operations[OperationType.Post].Parameters[0].Name); - Assert.NotNull(document.Paths["/resource"].Operations[OperationType.Post].Parameters[0].Schema); - Assert.Equal(JsonSchemaTypes.String, document.Paths["/resource"].Operations[OperationType.Post].Parameters[0].Schema.Type); + Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); + Assert.Equal("ParameterInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].Parameters[0].Name); + Assert.NotNull(document.Paths["/resource"].Operations[HttpMethod.Post].Parameters[0].Schema); + Assert.Equal(JsonSchemaTypes.String, document.Paths["/resource"].Operations[HttpMethod.Post].Parameters[0].Schema.Type); } [Fact] @@ -419,7 +418,7 @@ public void GetSwagger_SetsOperationIdToNull_IfActionHasNoEndpointMetadata() var document = subject.GetSwagger("v1"); - Assert.Null(document.Paths["/resource"].Operations[OperationType.Post].OperationId); + Assert.Null(document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); } [Fact] @@ -435,7 +434,7 @@ public void GetSwagger_SetsDeprecated_IfActionHasObsoleteAttribute() var document = subject.GetSwagger("v1"); - Assert.True(document.Paths["/resource"].Operations[OperationType.Post].Deprecated); + Assert.True(document.Paths["/resource"].Operations[HttpMethod.Post].Deprecated); } [Theory] @@ -468,7 +467,7 @@ public void GetSwagger_GeneratesParameters_ForApiParametersThatAreNotBoundToBody var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; var parameter = Assert.Single(operation.Parameters); Assert.Equal(expectedParameterLocation, parameter.In); } @@ -518,7 +517,7 @@ public void GetSwagger_IgnoresParameters_IfActionParameterHasBindNeverAttribute( var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Empty(operation.Parameters); } @@ -546,7 +545,7 @@ public void GetSwagger_IgnoresParameters_IfActionParameterHasSwaggerIgnoreAttrib var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Empty(operation.Parameters); } @@ -586,7 +585,7 @@ public void GetSwagger_IgnoresParameters_IfActionParameterIsIllegalHeaderParamet var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Get]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Get]; var parameter = Assert.Single(operation.Parameters); Assert.Equal("param", parameter.Name); } @@ -656,7 +655,7 @@ public void GetSwagger_GenerateParametersSchemas_IfActionParameterIsIllegalHeade var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Get]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Get]; Assert.Null(operation.Parameters.Single(p => p.Name == illegalParameterName).Schema); Assert.NotNull(operation.Parameters.Single(p => p.Name == "param").Schema); } @@ -685,7 +684,7 @@ public void GetSwagger_SetsParameterRequired_IfApiParameterIsBoundToPath() var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.True(operation.Parameters.First().Required); } @@ -718,7 +717,7 @@ public void GetSwagger_SetsParameterRequired_IfActionParameterHasRequiredOrBindR var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; var parameter = Assert.Single(operation.Parameters); Assert.Equal(expectedRequired, parameter.Required); } @@ -748,7 +747,7 @@ public void GetSwagger_SetsParameterRequired_IfActionParameterHasRequiredMember( var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; var parameter = Assert.Single(operation.Parameters); Assert.True(parameter.Required); } @@ -788,7 +787,7 @@ static void Execute(object obj) { } var document = subject.GetSwagger("v1"); - Assert.Equal(isRequired, document.Paths["/resource"].Operations[OperationType.Post].RequestBody.Required); + Assert.Equal(isRequired, document.Paths["/resource"].Operations[HttpMethod.Post].RequestBody.Required); } [Fact] @@ -815,7 +814,7 @@ public void GetSwagger_SetsParameterTypeToString_IfApiParameterHasNoCorrespondin var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; var parameter = Assert.Single(operation.Parameters); Assert.Equal(JsonSchemaTypes.String, parameter.Schema.Type); } @@ -848,7 +847,7 @@ public void GetSwagger_GeneratesRequestBody_ForFirstApiParameterThatIsBoundToBod var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.NotNull(operation.RequestBody); Assert.Equal(["application/json"], operation.RequestBody.Content.Keys); var mediaType = operation.RequestBody.Content["application/json"]; @@ -888,7 +887,7 @@ public void GetSwagger_SetsRequestBodyRequired_IfActionParameterHasRequiredOrBin var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal(expectedRequired, operation.RequestBody.Required); } @@ -923,7 +922,7 @@ public void GetSwagger_GeneratesRequestBody_ForApiParametersThatAreBoundToForm() var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.NotNull(operation.RequestBody); Assert.Equal(["multipart/form-data"], operation.RequestBody.Content.Keys); var mediaType = operation.RequestBody.Content["multipart/form-data"]; @@ -959,7 +958,7 @@ public void GetSwagger_SetsRequestBodyContentTypesFromAttribute_IfActionHasConsu var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal(["application/someMediaType"], operation.RequestBody.Content.Keys); } @@ -1004,7 +1003,7 @@ public void GetSwagger_GeneratesResponses_ForSupportedResponseTypes() var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal(["200", "400", "422", "default"], operation.Responses.Keys); var response200 = operation.Responses["200"]; Assert.Equal("OK", response200.Description); @@ -1047,7 +1046,7 @@ public void GetSwagger_SetsResponseContentType_WhenActionHasFileResult() var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; var content = operation.Responses["200"].Content.FirstOrDefault(); Assert.Equal("application/zip", content.Key); Assert.Equal("binary", content.Value.Schema.Format); @@ -1078,7 +1077,7 @@ public void GetSwagger_SetsResponseContentTypesFromAttribute_IfActionHasProduces var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal(["application/someMediaType"], operation.Responses["200"].Content.Keys); } @@ -1195,7 +1194,7 @@ public void GetSwagger_SupportsOption_IgnoreObsoleteActions() var document = subject.GetSwagger("v1"); Assert.Equal(["/resource"], [.. document.Paths.Keys]); - Assert.Equal([OperationType.Post], document.Paths["/resource"].Operations.Keys); + Assert.Equal([HttpMethod.Post], document.Paths["/resource"].Operations.Keys); Assert.Single(document.Paths["/resource"].Operations); } @@ -1253,7 +1252,7 @@ public void GetSwagger_SupportsOption_TagSelector() var document = subject.GetSwagger("v1"); - Assert.Equal(["resource"], [.. document.Paths["/resource"].Operations[OperationType.Post].Tags?.Select(t => t.Name)]); + Assert.Equal(["resource"], [.. document.Paths["/resource"].Operations[HttpMethod.Post].Tags?.Select(t => t.Reference.Id)]); } [Fact] @@ -1277,7 +1276,7 @@ public void GetSwagger_CanReadTagsFromMetadata() var document = subject.GetSwagger("v1"); - Assert.Equal(["Some", "Tags", "Here"], [.. document.Paths["/resource"].Operations[OperationType.Post].Tags?.Select(t => t.Name)]); + Assert.Equal(["Some", "Tags", "Here"], [.. document.Paths["/resource"].Operations[HttpMethod.Post].Tags?.Select(t => t.Reference.Id)]); } [Fact] @@ -1301,7 +1300,7 @@ public void GetSwagger_CanReadEndpointSummaryFromMetadata() var document = subject.GetSwagger("v1"); - Assert.Equal("A Test Summary", document.Paths["/resource"].Operations[OperationType.Post].Summary); + Assert.Equal("A Test Summary", document.Paths["/resource"].Operations[HttpMethod.Post].Summary); } [Fact] @@ -1325,7 +1324,7 @@ public void GetSwagger_CanReadEndpointDescriptionFromMetadata() var document = subject.GetSwagger("v1"); - Assert.Equal("A Test Description", document.Paths["/resource"].Operations[OperationType.Post].Description); + Assert.Equal("A Test Description", document.Paths["/resource"].Operations[HttpMethod.Post].Description); } [Fact] @@ -1353,7 +1352,7 @@ public void GetSwagger_SupportsOption_ConflictingActionsResolver() var document = subject.GetSwagger("v1"); Assert.Equal(["/resource"], [.. document.Paths.Keys]); - Assert.Equal([OperationType.Post], document.Paths["/resource"].Operations.Keys); + Assert.Equal([HttpMethod.Post], document.Paths["/resource"].Operations.Keys); Assert.Single(document.Paths["/resource"].Operations); } @@ -1396,7 +1395,7 @@ public void GetSwagger_SupportsOption_DescribeAllParametersInCamelCase( var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; var parameter = Assert.Single(operation.Parameters); Assert.Equal(expectedOpenApiParameterName, parameter.Name); } @@ -1465,7 +1464,7 @@ public void GetSwagger_SupportsOption_DescribeAllParametersInCamelCase_ForParame var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; var parameter = Assert.Single(operation.Parameters); Assert.Equal(expectedOpenApiParameterName, parameter.Name); } @@ -1505,7 +1504,7 @@ public void GetSwagger_SupportsOption_SecuritySchemes() { ["v1"] = new OpenApiInfo { Version = "V1", Title = "Test API" } }, - SecuritySchemes = new Dictionary + SecuritySchemes = new Dictionary { ["basic"] = new OpenApiSecurityScheme { Type = SecuritySchemeType.Http, Scheme = "basic" } } @@ -1518,7 +1517,7 @@ public void GetSwagger_SupportsOption_SecuritySchemes() } [Theory] - [InlineData(false, new string[] { })] + [InlineData(false, null)] [InlineData(true, new string[] { "Bearer" })] public async Task GetSwagger_SupportsOption_InferSecuritySchemes( bool inferSecuritySchemes, @@ -1543,11 +1542,11 @@ public async Task GetSwagger_SupportsOption_InferSecuritySchemes( var document = await subject.GetSwaggerAsync("v1"); - Assert.Equal(expectedSecuritySchemeNames, document.Components.SecuritySchemes.Keys); + Assert.Equal(expectedSecuritySchemeNames, document.Components.SecuritySchemes?.Keys); } [Theory] - [InlineData(false, new string[] { })] + [InlineData(false, null)] [InlineData(true, new string[] { "Bearer", "Cookies" })] public async Task GetSwagger_SupportsOption_SecuritySchemesSelector( bool inferSecuritySchemes, @@ -1571,13 +1570,13 @@ public async Task GetSwagger_SupportsOption_SecuritySchemesSelector( authenticationSchemes .ToDictionary( (authScheme) => authScheme.Name, - (authScheme) => new OpenApiSecurityScheme()) + (authScheme) => new OpenApiSecurityScheme() as IOpenApiSecurityScheme) } ); var document = await subject.GetSwaggerAsync("v1"); - Assert.Equal(expectedSecuritySchemeNames, document.Components.SecuritySchemes.Keys); + Assert.Equal(expectedSecuritySchemeNames, document.Components.SecuritySchemes?.Keys); } [Fact] @@ -1611,11 +1610,10 @@ public void GetSwagger_SupportsOption_ParameterFilters() var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.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); + Assert.Equal("bar", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1649,11 +1647,11 @@ public void GetSwagger_SupportsOption_RequestBodyFilters() var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.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); + Assert.Equal("bar", ((JsonNodeExtension)operation.RequestBody.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.RequestBody.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1680,11 +1678,11 @@ public void GetSwagger_SupportsOption_OperationFilters() var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal(2, operation.Extensions.Count); - Assert.Equal("bar", ((OpenApiString)operation.Extensions["X-foo"]).Value); - Assert.Equal("v1", ((OpenApiString)operation.Extensions["X-docName"]).Value); + Assert.Equal("bar", ((JsonNodeExtension)operation.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1710,8 +1708,8 @@ public void GetSwagger_SupportsOption_DocumentFilters() Assert.Equal(2, document.Extensions.Count); Assert.Contains("ComplexType", document.Components.Schemas.Keys); - Assert.Equal("bar", ((OpenApiString)document.Extensions["X-foo"]).Value); - Assert.Equal("v1", ((OpenApiString)document.Extensions["X-docName"]).Value); + Assert.Equal("bar", ((JsonNodeExtension)document.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)document.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1738,11 +1736,11 @@ public async Task GetSwaggerAsync_SupportsOption_OperationFilters() var document = await subject.GetSwaggerAsync("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal(2, operation.Extensions.Count); - Assert.Equal("bar", ((OpenApiString)operation.Extensions["X-foo"]).Value); - Assert.Equal("v1", ((OpenApiString)operation.Extensions["X-docName"]).Value); + Assert.Equal("bar", ((JsonNodeExtension)operation.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1769,11 +1767,11 @@ public async Task GetSwaggerAsync_SupportsOption_OperationAsyncFilters() var document = await subject.GetSwaggerAsync("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal(2, operation.Extensions.Count); - Assert.Equal("bar", ((OpenApiString)operation.Extensions["X-foo"]).Value); - Assert.Equal("v1", ((OpenApiString)operation.Extensions["X-docName"]).Value); + Assert.Equal("bar", ((JsonNodeExtension)operation.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1799,8 +1797,8 @@ public async Task GetSwaggerAsync_SupportsOption_DocumentAsyncFilters() Assert.Equal(2, document.Extensions.Count); Assert.Contains("ComplexType", document.Components.Schemas.Keys); - Assert.Equal("bar", ((OpenApiString)document.Extensions["X-foo"]).Value); - Assert.Equal("v1", ((OpenApiString)document.Extensions["X-docName"]).Value); + Assert.Equal("bar", ((JsonNodeExtension)document.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)document.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1826,8 +1824,8 @@ public async Task GetSwaggerAsync_SupportsOption_DocumentFilters() Assert.Equal(2, document.Extensions.Count); Assert.Contains("ComplexType", document.Components.Schemas.Keys); - Assert.Equal("bar", ((OpenApiString)document.Extensions["X-foo"]).Value); - Assert.Equal("v1", ((OpenApiString)document.Extensions["X-docName"]).Value); + Assert.Equal("bar", ((JsonNodeExtension)document.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)document.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1861,11 +1859,11 @@ public async Task GetSwaggerAsync_SupportsOption_RequestBodyAsyncFilters() var document = await subject.GetSwaggerAsync("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.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); + Assert.Equal("bar", ((JsonNodeExtension)operation.RequestBody.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.RequestBody.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1899,11 +1897,11 @@ public async Task GetSwaggerAsync_SupportsOption_RequestBodyFilters() var document = await subject.GetSwaggerAsync("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.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); + Assert.Equal("bar", ((JsonNodeExtension)operation.RequestBody.Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.RequestBody.Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1937,11 +1935,11 @@ public async Task GetSwaggerAsync_SupportsOption_ParameterFilters() var document = await subject.GetSwaggerAsync("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.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); + Assert.Equal("bar", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-docName"]).Node.GetValue()); } [Fact] @@ -1975,11 +1973,11 @@ public async Task GetSwaggerAsync_SupportsOption_ParameterAsyncFilters() var document = await subject.GetSwaggerAsync("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.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); + Assert.Equal("bar", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-foo"]).Node.GetValue()); + Assert.Equal("v1", ((JsonNodeExtension)operation.Parameters[0].Extensions["X-docName"]).Node.GetValue()); } [Theory] @@ -2079,7 +2077,7 @@ public void GetSwagger_Works_As_Expected_When_FromForm_Attribute_Not_Used_With_I Assert.Equal("Test API", document.Info.Title); Assert.Equal(["/resource"], [.. document.Paths.Keys]); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.NotNull(operation.Parameters); Assert.Equal(2, operation.Parameters.Count); Assert.Equal("param1", operation.Parameters[0].Name); @@ -2129,7 +2127,7 @@ public void GetSwagger_Works_As_Expected_When_FromForm_Attribute_With_SwaggerIgn ); var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.NotNull(operation.RequestBody); Assert.Equal(["multipart/form-data"], operation.RequestBody.Content.Keys); var mediaType = operation.RequestBody.Content["multipart/form-data"]; @@ -2164,13 +2162,13 @@ public void GetSwagger_Works_As_Expected_When_FromFormObject() ); var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.NotNull(operation.RequestBody); Assert.Equal(["multipart/form-data"], operation.RequestBody.Content.Keys); var mediaType = operation.RequestBody.Content["multipart/form-data"]; Assert.NotNull(mediaType.Schema); - Assert.NotNull(mediaType.Schema.Reference); - Assert.Equal(nameof(SwaggerIngoreAnnotatedType), mediaType.Schema.Reference.Id); + var reference = Assert.IsType(mediaType.Schema); + Assert.Equal(nameof(SwaggerIngoreAnnotatedType), reference.Reference.Id); Assert.Empty(mediaType.Encoding); } @@ -2206,15 +2204,15 @@ public void GetSwagger_Works_As_Expected_When_FromFormObject_AndString() ); var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.NotNull(operation.RequestBody); Assert.Equal(["multipart/form-data"], operation.RequestBody.Content.Keys); var mediaType = operation.RequestBody.Content["multipart/form-data"]; Assert.NotNull(mediaType.Schema); Assert.NotEmpty(mediaType.Schema.AllOf); Assert.Equal(2, mediaType.Schema.AllOf.Count); - Assert.NotNull(mediaType.Schema.AllOf[0].Reference); - Assert.Equal(nameof(SwaggerIngoreAnnotatedType), mediaType.Schema.AllOf[0].Reference.Id); + var reference = Assert.IsType(mediaType.Schema.AllOf[0]); + Assert.Equal(nameof(SwaggerIngoreAnnotatedType), reference.Reference.Id); Assert.NotEmpty(mediaType.Schema.AllOf[1].Properties); Assert.Equal(["param2"], mediaType.Schema.AllOf[1].Properties.Keys); Assert.NotEmpty(mediaType.Encoding); @@ -2246,11 +2244,11 @@ public void GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsS ); var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.Equal("param1", operation.Parameters[0].Name); Assert.NotNull(operation.Parameters[0].Schema); - Assert.NotNull(operation.Parameters[0].Schema.Reference); - Assert.Equal(nameof(IntEnum), operation.Parameters[0].Schema.Reference.Id); + var reference = Assert.IsType(operation.Parameters[0].Schema); + Assert.Equal(nameof(IntEnum), reference.Reference.Id); } [Fact] @@ -2297,7 +2295,7 @@ public void GetSwagger_Copies_Description_From_GeneratedSchema() ); var document = subject.GetSwagger("v1"); - var operation = document.Paths["/resource"].Operations[OperationType.Post]; + var operation = document.Paths["/resource"].Operations[HttpMethod.Post]; Assert.NotEmpty(operation.Parameters); Assert.Equal(nameof(TypeWithDefaultAttributeOnEnum.EnumWithDefault), operation.Parameters[0].Name); Assert.Equal(document.Components.Schemas[nameof(IntEnum)].Description, operation.Parameters[0].Description); @@ -2359,13 +2357,15 @@ public void GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithSe var document = subject.GetSwagger("v1"); - Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[OperationType.Post].OperationId); - var content = Assert.Single(document.Paths["/resource"].Operations[OperationType.Post].RequestBody.Content); + Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); + var content = Assert.Single(document.Paths["/resource"].Operations[HttpMethod.Post].RequestBody.Content); Assert.Equal("application/someMediaType", content.Key); Assert.NotNull(content.Value.Schema); Assert.NotNull(content.Value.Schema.AllOf); - Assert.Equal("TestDto", content.Value.Schema.AllOf[0].Reference.Id); - Assert.Equal("TypeWithDefaultAttributeOnEnum", content.Value.Schema.AllOf[1].Reference.Id); + var reference = Assert.IsType(content.Value.Schema.AllOf[0]); + Assert.Equal("TestDto", reference.Reference.Id); + reference = Assert.IsType(content.Value.Schema.AllOf[1]); + Assert.Equal("TypeWithDefaultAttributeOnEnum", reference.Reference.Id); } [Fact] @@ -2416,8 +2416,8 @@ public void GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIF var document = subject.GetSwagger("v1"); - Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[OperationType.Post].OperationId); - var content = Assert.Single(document.Paths["/resource"].Operations[OperationType.Post].RequestBody.Content); + Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); + var content = Assert.Single(document.Paths["/resource"].Operations[HttpMethod.Post].RequestBody.Content); Assert.Equal("application/someMediaType", content.Key); Assert.NotNull(content.Value.Schema); Assert.Equal(JsonSchemaTypes.Object, content.Value.Schema.Type); @@ -2478,8 +2478,8 @@ public void GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIF var document = subject.GetSwagger("v1"); - Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[OperationType.Post].OperationId); - var content = Assert.Single(document.Paths["/resource"].Operations[OperationType.Post].RequestBody.Content); + Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); + var content = Assert.Single(document.Paths["/resource"].Operations[HttpMethod.Post].RequestBody.Content); Assert.Equal("application/someMediaType", content.Key); Assert.NotNull(content.Value.Schema); Assert.Equal(JsonSchemaTypes.Object, content.Value.Schema.Type); @@ -2542,8 +2542,8 @@ public void GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithSt var document = subject.GetSwagger("v1"); - Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[OperationType.Post].OperationId); - var content = Assert.Single(document.Paths["/resource"].Operations[OperationType.Post].RequestBody.Content); + Assert.Equal("OperationIdSetInMetadata", document.Paths["/resource"].Operations[HttpMethod.Post].OperationId); + var content = Assert.Single(document.Paths["/resource"].Operations[HttpMethod.Post].RequestBody.Content); Assert.Equal("application/someMediaType", content.Key); Assert.NotNull(content.Value.Schema); Assert.Equal(JsonSchemaTypes.Object, content.Value.Schema.Type); @@ -2591,7 +2591,7 @@ public void GetSwagger_OpenApiOperationWithRawContent_IsHandled() Assert.Equal("V1", document.Info.Version); Assert.Equal("Test API", document.Info.Title); Assert.Equal(["/resource"], [.. document.Paths.Keys]); - Assert.Equal([OperationType.Post], document.Paths["/resource"].Operations.Keys); + Assert.Equal([HttpMethod.Post], document.Paths["/resource"].Operations.Keys); Assert.Single(document.Paths["/resource"].Operations); } diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj index 818f4af5a4..d69699d6a0 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/Swashbuckle.AspNetCore.SwaggerGen.Test.csproj @@ -9,6 +9,10 @@ $(MSBuildThisFileDirectory)..\..\src\Swashbuckle.AspNetCore.Swagger\Swashbuckle.AspNetCore.Swagger.snk + + + + diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/VerifyTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/VerifyTests.cs index ef61c20f2f..a8ae6dd7ab 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/VerifyTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/VerifyTests.cs @@ -10,8 +10,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.AspNetCore.Routing; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Writers; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen.Test.Fixtures; using Swashbuckle.AspNetCore.TestSupport; diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsDocumentFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsDocumentFilterTests.cs index 54602b782f..c87ecc54ba 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsDocumentFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsDocumentFilterTests.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsExampleHelperTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsExampleHelperTests.cs index 2b56518689..20fac1da14 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsExampleHelperTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsExampleHelperTests.cs @@ -1,5 +1,5 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using System.Text.Json; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -19,16 +19,17 @@ public void Create_Builds_OpenApiArrayJson_When_Not_String_Type_And_Data_Is_Arra Assert.NotNull(example); - var actual = Assert.IsType(example); + Assert.Equal(JsonValueKind.Array, example.GetValueKind()); + var actual = example.AsArray(); Assert.Equal(3, actual.Count); - var item1 = Assert.IsType(actual[0]); - var item2 = Assert.IsType(actual[1]); - var item3 = Assert.IsType(actual[2]); - Assert.Equal("one", item1.Value); - Assert.Equal("two", item2.Value); - Assert.Equal("three", item3.Value); + Assert.Equal(JsonValueKind.String, actual[0].GetValueKind()); + Assert.Equal(JsonValueKind.String, actual[1].GetValueKind()); + Assert.Equal(JsonValueKind.String, actual[2].GetValueKind()); + Assert.Equal("one", actual[0].GetValue()); + Assert.Equal("two", actual[1].GetValue()); + Assert.Equal("three", actual[2].GetValue()); } [Theory] @@ -46,8 +47,8 @@ public void Create_Builds_OpenApiString_When_Type_String(string exampleString) Assert.NotNull(example); - var actual = Assert.IsType(example); - Assert.Equal(actual.Value, exampleString); + Assert.Equal(JsonValueKind.String, example.GetValueKind()); + Assert.Equal(exampleString, example.GetValue()); } [Fact] @@ -59,10 +60,7 @@ public void Create_Returns_Null_When_Type_String_And_Value_Is_Null() var example = XmlCommentsExampleHelper.Create( schemaRepository, schema, null); - Assert.NotNull(example); - - var actual = Assert.IsType(example); - Assert.Equal(AnyType.Null, actual.AnyType); + Assert.Null(example); } [Fact] @@ -83,9 +81,7 @@ public void Create_Returns_Null_When_Type_String_And_Value_Null_String_Literal() schemaRepository, schema, "null"); Assert.NotNull(example); - - var actual = Assert.IsType(example); - Assert.Equal(AnyType.Null, actual.AnyType); + Assert.Equal("null", example.GetValue()); } [Fact] @@ -97,8 +93,8 @@ public void Create_Allows_Schema_To_Be_Null() Assert.NotNull(example); - var actual = Assert.IsType(example); - Assert.Empty(actual); + Assert.Equal(JsonValueKind.Array, example.GetValueKind()); + Assert.Empty(example.AsArray()); } [Fact] @@ -112,9 +108,7 @@ public void Create_Builds_OpenApiString_When_Type_Integer() schemaRepository, schema, exampleString); Assert.NotNull(example); - - var actual = Assert.IsType(example); - Assert.Equal(1, actual.Value); + Assert.Equal(1, example.GetValue()); } [Fact] diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsOperationFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsOperationFilterTests.cs index 8a06b6f25a..47b33d182b 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsOperationFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsOperationFilterTests.cs @@ -1,6 +1,6 @@ using System.Xml.XPath; using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.TestSupport; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -14,7 +14,7 @@ public void Apply_SetsSummaryAndDescription_FromActionSummaryAndRemarksTags() var methodInfo = typeof(FakeControllerWithXmlComments) .GetMethod(nameof(FakeControllerWithXmlComments.ActionWithSummaryAndRemarksTags)); var apiDescription = ApiDescriptionFactory.Create(methodInfo: methodInfo, groupName: "v1", httpMethod: "POST", relativePath: "resource"); - var filterContext = new OperationFilterContext(apiDescription, null, null, methodInfo); + var filterContext = new OperationFilterContext(apiDescription, null, null, null, methodInfo); Subject().Apply(operation, filterContext); @@ -29,7 +29,7 @@ public void Apply_SetsSummaryAndDescription_FromUnderlyingGenericTypeActionSumma var methodInfo = typeof(FakeConstructedControllerWithXmlComments) .GetMethod(nameof(FakeConstructedControllerWithXmlComments.ActionWithSummaryAndResponseTags)); var apiDescription = ApiDescriptionFactory.Create(methodInfo: methodInfo, groupName: "v1", httpMethod: "POST", relativePath: "resource"); - var filterContext = new OperationFilterContext(apiDescription, null, null, methodInfo); + var filterContext = new OperationFilterContext(apiDescription, null, null, null, methodInfo); Subject().Apply(operation, filterContext); @@ -55,12 +55,12 @@ public void Apply_SetsResponseDescription_FromActionOrControllerResponseTags() groupName: "v1", httpMethod: "POST", relativePath: "resource", - supportedResponseTypes: new[] - { + supportedResponseTypes: + [ new ApiResponseType { StatusCode = 200 }, new ApiResponseType { StatusCode = 400 }, - }); - var filterContext = new OperationFilterContext(apiDescription, null, null, methodInfo: methodInfo); + ]); + var filterContext = new OperationFilterContext(apiDescription, null, null, null, methodInfo: methodInfo); Subject().Apply(operation, filterContext); diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs index 2ddb64765a..31f4f1ef71 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsParameterFilterTests.cs @@ -1,6 +1,6 @@ using System.Xml.XPath; using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; #if !NET10_0_OR_GREATER using Swashbuckle.AspNetCore.TestSupport; #endif @@ -17,13 +17,14 @@ public void Apply_SetsDescriptionAndExample_FromActionParamTag() .GetMethod(nameof(FakeControllerWithXmlComments.ActionWithParamTags)) .GetParameters()[0]; var apiParameterDescription = new ApiParameterDescription { }; - var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, parameterInfo: parameterInfo); + var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, null, parameterInfo: parameterInfo); Subject().Apply(parameter, filterContext); Assert.Equal("Description for param1", parameter.Description); Assert.NotNull(parameter.Example); - Assert.Equal("\"Example for \\\"param1\\\"\"", parameter.Example.ToJson()); + + Assert.Equal("\"Example for \\u0022param1\\u0022\"", parameter.Example.ToJson()); } [Fact] @@ -34,13 +35,14 @@ public void Apply_SetsDescriptionAndExample_FromUriTypeActionParamTag() .GetMethod(nameof(FakeControllerWithXmlComments.ActionWithParamTags)) .GetParameters()[1]; var apiParameterDescription = new ApiParameterDescription { }; - var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, parameterInfo: parameterInfo); + var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, null, parameterInfo: parameterInfo); Subject().Apply(parameter, filterContext); Assert.Equal("Description for param2", parameter.Description); Assert.NotNull(parameter.Example); - Assert.Equal("\"http://test.com/?param1=1¶m2=2\"", parameter.Example.ToJson()); + + Assert.Equal("\"http://test.com/?param1=1\\u0026param2=2\"", parameter.Example.ToJson()); } [Fact] @@ -51,13 +53,14 @@ public void Apply_SetsDescriptionAndExample_FromUnderlyingGenericTypeActionParam .GetMethod(nameof(FakeConstructedControllerWithXmlComments.ActionWithParamTags)) .GetParameters()[0]; var apiParameterDescription = new ApiParameterDescription { }; - var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, parameterInfo: parameterInfo); + var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, null, parameterInfo: parameterInfo); Subject().Apply(parameter, filterContext); Assert.Equal("Description for param1", parameter.Description); Assert.NotNull(parameter.Example); - Assert.Equal("\"Example for \\\"param1\\\"\"", parameter.Example.ToJson()); + + Assert.Equal("\"Example for \\u0022param1\\u0022\"", parameter.Example.ToJson()); } [Fact] @@ -66,7 +69,7 @@ public void Apply_SetsDescriptionAndExample_FromPropertySummaryAndExampleTags() var parameter = new OpenApiParameter { Schema = new OpenApiSchema { Type = JsonSchemaTypes.String, Description = "schema-level description" } }; var propertyInfo = typeof(XmlAnnotatedType).GetProperty(nameof(XmlAnnotatedType.StringProperty)); var apiParameterDescription = new ApiParameterDescription { }; - var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, propertyInfo: propertyInfo); + var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, null, propertyInfo: propertyInfo); Subject().Apply(parameter, filterContext); @@ -82,14 +85,15 @@ public void Apply_SetsDescriptionAndExample_FromUriTypePropertySummaryAndExample var parameter = new OpenApiParameter { Schema = new OpenApiSchema { Type = JsonSchemaTypes.String, Description = "schema-level description" } }; var propertyInfo = typeof(XmlAnnotatedType).GetProperty(nameof(XmlAnnotatedType.StringPropertyWithUri)); var apiParameterDescription = new ApiParameterDescription { }; - var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, propertyInfo: propertyInfo); + var filterContext = new ParameterFilterContext(apiParameterDescription, null, null, null, propertyInfo: propertyInfo); Subject().Apply(parameter, filterContext); Assert.Equal("Summary for StringPropertyWithUri", parameter.Description); Assert.Null(parameter.Schema.Description); Assert.NotNull(parameter.Example); - Assert.Equal("\"https://test.com/a?b=1&c=2\"", parameter.Example.ToJson()); + + Assert.Equal("\"https://test.com/a?b=1\\u0026c=2\"", parameter.Example.ToJson()); } private static XmlCommentsParameterFilter Subject() diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs index bf08819578..0c141fd88d 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsRequestBodyFilterTests.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.TestSupport; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -26,13 +26,14 @@ public void Apply_SetsDescriptionAndExample_FromActionParamTag() { ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo } }; - var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, filterContext); Assert.Equal("Description for param1", requestBody.Description); Assert.NotNull(requestBody.Content["application/json"].Example); - Assert.Equal("\"Example for \\\"param1\\\"\"", requestBody.Content["application/json"].Example.ToJson()); + + Assert.Equal("\"Example for \\u0022param1\\u0022\"", requestBody.Content["application/json"].Example.ToJson()); } [Fact] @@ -52,13 +53,14 @@ public void Apply_SetsDescriptionAndExample_FromUnderlyingGenericTypeActionParam { ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo } }; - var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, filterContext); Assert.Equal("Description for param1", requestBody.Description); Assert.NotNull(requestBody.Content["application/json"].Example); - Assert.Equal("\"Example for \\\"param1\\\"\"", requestBody.Content["application/json"].Example.ToJson()); + + Assert.Equal("\"Example for \\u0022param1\\u0022\"", requestBody.Content["application/json"].Example.ToJson()); } [Fact] @@ -75,7 +77,7 @@ public void Apply_SetsDescriptionAndExample_FromPropertySummaryAndExampleTags() { ModelMetadata = ModelMetadataFactory.CreateForProperty(typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringProperty)) }; - var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, filterContext); @@ -99,13 +101,14 @@ public void Apply_SetsDescriptionAndExample_FromUriTypePropertySummaryAndExample { ModelMetadata = ModelMetadataFactory.CreateForProperty(typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringPropertyWithUri)) }; - var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, filterContext); Assert.Equal("Summary for StringPropertyWithUri", requestBody.Description); Assert.NotNull(requestBody.Content["application/json"].Example); - Assert.Equal("\"https://test.com/a?b=1&c=2\"", requestBody.Content["application/json"].Example.ToJson()); + + Assert.Equal("\"https://test.com/a?b=1\\u0026c=2\"", requestBody.Content["application/json"].Example.ToJson()); } [Fact] @@ -125,7 +128,7 @@ public void Apply_SetsDescription_ForParameterFromBody() { ParameterDescriptor = new ControllerParameterDescriptor { ParameterInfo = parameterInfo } }; - var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null); + var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null, null); Subject().Apply(requestBody, filterContext); @@ -148,7 +151,7 @@ public void Apply_SetsDescription_ForParameterFromForm() Schema = new OpenApiSchema { Type = JsonSchemaTypes.String, - Properties = new Dictionary() + Properties = new Dictionary() { [parameterInfo.Name] = new OpenApiSchema() } @@ -163,7 +166,7 @@ public void Apply_SetsDescription_ForParameterFromForm() Name = parameterInfo.Name, Source = BindingSource.Form }; - var filterContext = new RequestBodyFilterContext(null, [bodyParameterDescription], null, null); + var filterContext = new RequestBodyFilterContext(null, [bodyParameterDescription], null, null, null); Subject().Apply(requestBody, filterContext); diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs index ca2a3db180..11d6337651 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/XmlComments/XmlCommentsSchemaFilterTests.cs @@ -1,9 +1,6 @@ using System.Globalization; using System.Xml.XPath; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.TestSupport; - -using JsonSchemaType = string; +using Microsoft.OpenApi; namespace Swashbuckle.AspNetCore.SwaggerGen.Test; @@ -67,8 +64,6 @@ public void Apply_SetsDescription_FromPropertySummaryTag( { typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.GuidProperty), JsonSchemaTypes.String, "\"d3966535-2637-48fa-b911-e3c27405ee09\"" }, { typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringProperty), JsonSchemaTypes.String, "\"Example for StringProperty\"" }, { typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.ObjectProperty), JsonSchemaTypes.Object, "{\n \"prop1\": 1,\n \"prop2\": \"foobar\"\n}" }, - { typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringPropertyWithNullExample), JsonSchemaTypes.String, "null" }, - { typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringPropertyWithUri), JsonSchemaTypes.String, "\"https://test.com/a?b=1&c=2\"" }, { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.BoolProperty), JsonSchemaTypes.Boolean, "true" }, { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.IntProperty), JsonSchemaTypes.Integer, "10" }, { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.LongProperty), JsonSchemaTypes.Integer, "4294967295" }, @@ -79,8 +74,10 @@ public void Apply_SetsDescription_FromPropertySummaryTag( { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.GuidProperty), JsonSchemaTypes.String, "\"d3966535-2637-48fa-b911-e3c27405ee09\"" }, { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.StringProperty), JsonSchemaTypes.String, "\"Example for StringProperty\"" }, { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.ObjectProperty), JsonSchemaTypes.Object, "{\n \"prop1\": 1,\n \"prop2\": \"foobar\"\n}" }, - { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.StringPropertyWithNullExample), JsonSchemaTypes.String, "null" }, - { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.StringPropertyWithUri), JsonSchemaTypes.String, "\"https://test.com/a?b=1&c=2\"" }, + { typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringPropertyWithUri), JsonSchemaTypes.String, "\"https://test.com/a?b=1\\u0026c=2\"" }, + { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.StringPropertyWithUri), JsonSchemaTypes.String, "\"https://test.com/a?b=1\\u0026c=2\"" }, + { typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringPropertyWithNullExample), JsonSchemaTypes.String, "\"null\"" }, + { typeof(XmlAnnotatedRecord), nameof(XmlAnnotatedRecord.StringPropertyWithNullExample), JsonSchemaTypes.String, "\"null\"" }, }; [Theory] @@ -102,8 +99,7 @@ public void Apply_SetsExample_FromPropertyExampleTag( Subject().Apply(schema, filterContext); // Assert - Assert.NotNull(schema.Example); - Assert.Equal(expectedExampleAsJson, schema.Example.ToJson()); + Assert.Equal(expectedExampleAsJson, schema.Example?.ToJson()); } public static TheoryData Apply_DoesNotSetExample_WhenPropertyExampleTagIsNotProvided_Data => new() @@ -173,7 +169,8 @@ public void Apply_UsesInvariantCulture_WhenSettingExample( CultureInfo.CurrentCulture = defaultCulture; - Assert.Equal(expectedValue, schema.Example.GetType().GetProperty("Value").GetValue(schema.Example)); + Assert.NotNull(schema.Example); + Assert.Equal(expectedValue, schema.Example.GetValue()); } private static XmlCommentsSchemaFilter Subject() diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet10_0.verified.txt new file mode 100644 index 0000000000..6d14c6201c --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "application/someMediaType": { + "schema": { + "type": "string" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet8_0.verified.txt index d563468b10..6d14c6201c 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet8_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet9_0.verified.txt index d563468b10..6d14c6201c 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Body.DotNet9_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet10_0.verified.txt new file mode 100644 index 0000000000..bc6ffc3f3f --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet10_0.verified.txt @@ -0,0 +1,46 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "application/someMediaType": { + "schema": { + "type": "object", + "properties": { + "param": { + "type": "string" + } + } + }, + "encoding": { + "param": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet8_0.verified.txt index bae2a174da..bc6ffc3f3f 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet8_0.verified.txt @@ -37,5 +37,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet9_0.verified.txt index bae2a174da..bc6ffc3f3f 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasConsumesAttribute_bindingSourceId=Form.DotNet9_0.verified.txt @@ -37,5 +37,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet10_0.verified.txt new file mode 100644 index 0000000000..3273311954 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet10_0.verified.txt @@ -0,0 +1,35 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/zip": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet8_0.verified.txt index fb597ff815..3273311954 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet8_0.verified.txt @@ -26,5 +26,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet9_0.verified.txt index fb597ff815..3273311954 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasFileResult.DotNet9_0.verified.txt @@ -26,5 +26,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..5ec4767ac3 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet10_0.verified.txt @@ -0,0 +1,28 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + }, + "deprecated": true + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet8_0.verified.txt index e846f5db84..5ec4767ac3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet8_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet9_0.verified.txt index e846f5db84..5ec4767ac3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasObsoleteAttribute.DotNet9_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..919cb44f3b --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet10_0.verified.txt @@ -0,0 +1,35 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/someMediaType": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet8_0.verified.txt index 40f97e8104..919cb44f3b 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet8_0.verified.txt @@ -26,5 +26,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet9_0.verified.txt index 40f97e8104..919cb44f3b 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHasProducesAttribute.DotNet9_0.verified.txt @@ -26,5 +26,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet10_0.verified.txt new file mode 100644 index 0000000000..0ac5eeddeb --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet10_0.verified.txt @@ -0,0 +1,44 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param1", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "param2", + "in": "query", + "schema": { + "type": "string", + "format": "binary" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet8_0.verified.txt index beaf092287..0ac5eeddeb 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet8_0.verified.txt @@ -35,5 +35,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet9_0.verified.txt index beaf092287..0ac5eeddeb 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeButNotWithIFormFile.DotNet9_0.verified.txt @@ -35,5 +35,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet10_0.verified.txt new file mode 100644 index 0000000000..09943db9a0 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet10_0.verified.txt @@ -0,0 +1,46 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "NotIgnoredString": { + "type": "string" + } + } + }, + "encoding": { + "NotIgnoredString": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet8_0.verified.txt index 7bfe672606..09943db9a0 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet8_0.verified.txt @@ -37,5 +37,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet9_0.verified.txt index 7bfe672606..09943db9a0 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionHavingFromFormAttributeWithSwaggerIgnore.DotNet9_0.verified.txt @@ -37,5 +37,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..c4978dc754 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet10_0.verified.txt @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet8_0.verified.txt index d43830691c..c4978dc754 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet8_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet9_0.verified.txt index d43830691c..c4978dc754 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasBindNeverAttribute.DotNet9_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..c4978dc754 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet10_0.verified.txt @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet8_0.verified.txt index d43830691c..c4978dc754 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet8_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet9_0.verified.txt index d43830691c..c4978dc754 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionParameterHasSwaggerIgnoreAttribute.DotNet9_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithConsumesAttributeAndProvidedOpenApiOperation.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithConsumesAttributeAndProvidedOpenApiOperation.DotNet10_0.verified.txt new file mode 100644 index 0000000000..0477b2747b --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithConsumesAttributeAndProvidedOpenApiOperation.DotNet10_0.verified.txt @@ -0,0 +1,38 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "requestBody": { + "content": { + "application/someMediaType": { + "schema": { + "$ref": "#/components/schemas/TestDto" + } + } + } + }, + "responses": { } + } + } + }, + "components": { + "schemas": { + "TestDto": { + "type": "object", + "properties": { + "Prop1": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet10_0.verified.txt new file mode 100644 index 0000000000..564eaef913 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet10_0.verified.txt @@ -0,0 +1,28 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "operationId": "SomeEndpointName", + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet8_0.verified.txt index 881b2f804c..564eaef913 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet8_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet9_0.verified.txt index 881b2f804c..564eaef913 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithEndpointNameMetadata.DotNet9_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithParameterAndProvidedOpenApiOperation.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithParameterAndProvidedOpenApiOperation.DotNet10_0.verified.txt new file mode 100644 index 0000000000..215b43fba8 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithParameterAndProvidedOpenApiOperation.DotNet10_0.verified.txt @@ -0,0 +1,24 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "parameters": [ + { + "name": "ParameterInMetadata", + "schema": { + "type": "string" + } + } + ], + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithProducesAttributeAndProvidedOpenApiOperation.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithProducesAttributeAndProvidedOpenApiOperation.DotNet10_0.verified.txt new file mode 100644 index 0000000000..5701dd9909 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithProducesAttributeAndProvidedOpenApiOperation.DotNet10_0.verified.txt @@ -0,0 +1,40 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "responses": { + "200": { + "description": null, + "content": { + "application/someMediaType": { + "schema": { + "$ref": "#/components/schemas/TestDto" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "TestDto": { + "type": "object", + "properties": { + "Prop1": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithProvidedOpenApiMetadata.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithProvidedOpenApiMetadata.DotNet10_0.verified.txt new file mode 100644 index 0000000000..f9809c47a5 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithProvidedOpenApiMetadata.DotNet10_0.verified.txt @@ -0,0 +1,21 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "parameters": [ + { + "name": "ParameterInMetadata" + } + ], + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..b6f6dc6fe7 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt index d8feabf909..b6f6dc6fe7 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt index d8feabf909..b6f6dc6fe7 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..b6f6dc6fe7 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt index d8feabf909..b6f6dc6fe7 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt index d8feabf909..b6f6dc6fe7 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredBodyParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet10_0.verified.txt new file mode 100644 index 0000000000..4b47d6bf47 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet8_0.verified.txt index d01ccb87ff..4b47d6bf47 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet9_0.verified.txt index d01ccb87ff..4b47d6bf47 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredMember.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..4b47d6bf47 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt index d01ccb87ff..4b47d6bf47 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt index d01ccb87ff..4b47d6bf47 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithBindRequiredAttribute.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..4b47d6bf47 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt index d01ccb87ff..4b47d6bf47 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt index d01ccb87ff..4b47d6bf47 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRequiredQueryParameter_action=ActionWithParameterWithRequiredAttribute.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet10_0.verified.txt new file mode 100644 index 0000000000..ab92669e55 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet10_0.verified.txt @@ -0,0 +1,44 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "422": { + "description": "Unprocessable Content" + }, + "default": { + "description": "Error" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet8_0.verified.txt index 7ce9616bd4..ab92669e55 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet8_0.verified.txt @@ -35,5 +35,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet9_0.verified.txt index 7ce9616bd4..ab92669e55 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithReturnValueAndSupportedResponseTypes.DotNet9_0.verified.txt @@ -35,5 +35,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet10_0.verified.txt new file mode 100644 index 0000000000..78e049e122 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet10_0.verified.txt @@ -0,0 +1,28 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "operationId": "SomeRouteName", + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet8_0.verified.txt index 96e2b65032..78e049e122 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet8_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet9_0.verified.txt index 96e2b65032..78e049e122 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionWithRouteNameMetadata.DotNet9_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet10_0.verified.txt new file mode 100644 index 0000000000..6624ddf8a3 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "get": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet8_0.verified.txt index 1dc73c4cb6..6624ddf8a3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet8_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet9_0.verified.txt index 1dc73c4cb6..6624ddf8a3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAcceptFromHeaderParameter.DotNet9_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet10_0.verified.txt new file mode 100644 index 0000000000..6624ddf8a3 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "get": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet8_0.verified.txt index 1dc73c4cb6..6624ddf8a3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet8_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet9_0.verified.txt index 1dc73c4cb6..6624ddf8a3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithAuthorizationFromHeaderParameter.DotNet9_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet10_0.verified.txt new file mode 100644 index 0000000000..6624ddf8a3 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "get": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet8_0.verified.txt index 1dc73c4cb6..6624ddf8a3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet8_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet9_0.verified.txt index 1dc73c4cb6..6624ddf8a3 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ActionsWithIllegalHeaderParameters_action=ActionWithContentTypeFromHeaderParameter.DotNet9_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet10_0.verified.txt new file mode 100644 index 0000000000..ac07216149 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "get": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet8_0.verified.txt index 01c001ba5c..ac07216149 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet9_0.verified.txt index 01c001ba5c..ac07216149 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiDescriptionsWithMatchingGroupName.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet10_0.verified.txt new file mode 100644 index 0000000000..42b3ff16fb --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet10_0.verified.txt @@ -0,0 +1,31 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Foo" + ], + "requestBody": { + "content": { }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Foo" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet8_0.verified.txt index b960cc7d32..42b3ff16fb 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet8_0.verified.txt @@ -22,5 +22,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Foo" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet9_0.verified.txt index b960cc7d32..42b3ff16fb 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterDescriptionForBodyIsRequired.DotNet9_0.verified.txt @@ -22,5 +22,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Foo" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet10_0.verified.txt new file mode 100644 index 0000000000..9a842b7172 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet8_0.verified.txt index 12b0d9a064..9a842b7172 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet9_0.verified.txt index 12b0d9a064..9a842b7172 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterHasNoCorrespondingActionParameter.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet10_0.verified.txt new file mode 100644 index 0000000000..9a842b7172 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet8_0.verified.txt index 12b0d9a064..9a842b7172 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet9_0.verified.txt index 12b0d9a064..9a842b7172 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParameterIsBoundToPath.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet10_0.verified.txt new file mode 100644 index 0000000000..5fb54c13b8 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet10_0.verified.txt @@ -0,0 +1,53 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "param1": { + "type": "string" + }, + "param2": { + "type": "integer", + "format": "int32" + } + } + }, + "encoding": { + "param1": { + "style": "form" + }, + "param2": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet8_0.verified.txt index 3b3c806d7f..5fb54c13b8 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet8_0.verified.txt @@ -44,5 +44,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet9_0.verified.txt index 3b3c806d7f..5fb54c13b8 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreBoundToForm.DotNet9_0.verified.txt @@ -44,5 +44,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet10_0.verified.txt new file mode 100644 index 0000000000..c69a69d8a5 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet8_0.verified.txt index edd30d7ed8..c69a69d8a5 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet8_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet9_0.verified.txt index edd30d7ed8..c69a69d8a5 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Header.DotNet9_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet10_0.verified.txt new file mode 100644 index 0000000000..9a842b7172 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet10_0.verified.txt @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet8_0.verified.txt index 12b0d9a064..9a842b7172 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet8_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet9_0.verified.txt index 12b0d9a064..9a842b7172 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Path.DotNet9_0.verified.txt @@ -28,5 +28,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet10_0.verified.txt new file mode 100644 index 0000000000..8730d69c92 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet8_0.verified.txt index 2d0449f965..8730d69c92 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet8_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet9_0.verified.txt index 2d0449f965..8730d69c92 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=Query.DotNet9_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet10_0.verified.txt new file mode 100644 index 0000000000..8730d69c92 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet8_0.verified.txt index 2d0449f965..8730d69c92 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet8_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet9_0.verified.txt index 2d0449f965..8730d69c92 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ApiParametersThatAreNotBoundToBodyOrForm_bindingSourceId=null.DotNet9_0.verified.txt @@ -27,5 +27,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet10_0.verified.txt new file mode 100644 index 0000000000..c4978dc754 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet10_0.verified.txt @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet8_0.verified.txt index d43830691c..c4978dc754 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet8_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet9_0.verified.txt index d43830691c..c4978dc754 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.ConflictingActionsResolverIsSpecified.DotNet9_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..1240f3ab27 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet10_0.verified.txt @@ -0,0 +1,28 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "description": "A Test Description", + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet8_0.verified.txt index e99cc7c30a..1240f3ab27 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet8_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet9_0.verified.txt index e99cc7c30a..1240f3ab27 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasDescriptionAttribute.DotNet9_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..63a367e531 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet10_0.verified.txt @@ -0,0 +1,28 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "summary": "A Test Summary", + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet8_0.verified.txt index c9dbd1f23b..63a367e531 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet8_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet9_0.verified.txt index c9dbd1f23b..63a367e531 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasSummaryAttribute.DotNet9_0.verified.txt @@ -19,5 +19,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet10_0.verified.txt new file mode 100644 index 0000000000..22721ecaf5 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet10_0.verified.txt @@ -0,0 +1,35 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Some", + "Tags", + "Here" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Some" + }, + { + "name": "Tags" + }, + { + "name": "Here" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet8_0.verified.txt index 9a55caf777..22721ecaf5 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet8_0.verified.txt @@ -20,5 +20,16 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Some" + }, + { + "name": "Tags" + }, + { + "name": "Here" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet9_0.verified.txt index 9a55caf777..22721ecaf5 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.EndpointMetadataHasTags.DotNet9_0.verified.txt @@ -20,5 +20,16 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Some" + }, + { + "name": "Tags" + }, + { + "name": "Here" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet10_0.verified.txt new file mode 100644 index 0000000000..66ef5af646 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet10_0.verified.txt @@ -0,0 +1,65 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "EnumWithDefault", + "in": "query", + "description": "

Members:

  • Value2 - 2
  • Value4 - 4
  • Value8 - 8
", + "schema": { + "$ref": "#/components/schemas/IntEnum" + } + }, + { + "name": "EnumArrayWithDefault", + "in": "query", + "description": "

Members:

  • Value2 - 2
  • Value4 - 4
  • Value8 - 8
", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntEnum" + }, + "description": "

Members:

  • Value2 - 2
  • Value4 - 4
  • Value8 - 8
", + "default": [ + 4 + ] + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "IntEnum": { + "enum": [ + 2, + 4, + 8 + ], + "type": "integer", + "description": "

Members:

  • Value2 - 2
  • Value4 - 4
  • Value8 - 8
", + "format": "int32" + } + } + }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet8_0.verified.txt index 269352bca8..66ef5af646 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet8_0.verified.txt @@ -56,5 +56,10 @@ "format": "int32" } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet9_0.verified.txt index 269352bca8..66ef5af646 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Copies_Description_From_GeneratedSchema.DotNet9_0.verified.txt @@ -56,5 +56,10 @@ "format": "int32" } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIFormFile.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIFormFile.DotNet10_0.verified.txt new file mode 100644 index 0000000000..0b8be7e8df --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIFormFile.DotNet10_0.verified.txt @@ -0,0 +1,36 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "requestBody": { + "content": { + "application/someMediaType": { + "schema": { + "type": "object", + "properties": { + "param": { + "type": "string", + "format": "binary" + } + } + }, + "encoding": { + "param": { + "style": "form" + } + } + } + } + }, + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIFormFileCollection.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIFormFileCollection.DotNet10_0.verified.txt new file mode 100644 index 0000000000..13fdf02051 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithIFormFileCollection.DotNet10_0.verified.txt @@ -0,0 +1,39 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "requestBody": { + "content": { + "application/someMediaType": { + "schema": { + "type": "object", + "properties": { + "param": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + } + } + }, + "encoding": { + "param": { + "style": "form" + } + } + } + } + }, + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithSeveralFromForms.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithSeveralFromForms.DotNet10_0.verified.txt new file mode 100644 index 0000000000..1a5220d12f --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithSeveralFromForms.DotNet10_0.verified.txt @@ -0,0 +1,73 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "requestBody": { + "content": { + "application/someMediaType": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/TestDto" + }, + { + "$ref": "#/components/schemas/TypeWithDefaultAttributeOnEnum" + } + ] + } + } + } + }, + "responses": { } + } + } + }, + "components": { + "schemas": { + "IntEnum": { + "enum": [ + 2, + 4, + 8 + ], + "type": "integer", + "format": "int32" + }, + "TestDto": { + "type": "object", + "properties": { + "Prop1": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "TypeWithDefaultAttributeOnEnum": { + "type": "object", + "properties": { + "EnumWithDefault": { + "$ref": "#/components/schemas/IntEnum" + }, + "EnumArrayWithDefault": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IntEnum" + }, + "default": [ + 4 + ], + "nullable": true + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithStringFromForm.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithStringFromForm.DotNet10_0.verified.txt new file mode 100644 index 0000000000..fb4a0d9b0d --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_GenerateConsumesSchemas_ForProvidedOpenApiOperationWithStringFromForm.DotNet10_0.verified.txt @@ -0,0 +1,35 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "operationId": "OperationIdSetInMetadata", + "requestBody": { + "content": { + "application/someMediaType": { + "schema": { + "type": "object", + "properties": { + "param": { + "type": "string" + } + } + }, + "encoding": { + "param": { + "style": "form" + } + } + } + } + }, + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet10_0.verified.txt new file mode 100644 index 0000000000..3f7e0fca72 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet10_0.verified.txt @@ -0,0 +1,49 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/SwaggerIngoreAnnotatedType" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "SwaggerIngoreAnnotatedType": { + "type": "object", + "properties": { + "NotIgnoredString": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet8_0.verified.txt index fa3409d7a6..3f7e0fca72 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet8_0.verified.txt @@ -40,5 +40,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet9_0.verified.txt index fa3409d7a6..3f7e0fca72 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject.DotNet9_0.verified.txt @@ -40,5 +40,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet10_0.verified.txt new file mode 100644 index 0000000000..09cd6845a7 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet10_0.verified.txt @@ -0,0 +1,66 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SwaggerIngoreAnnotatedType" + }, + { + "type": "object", + "properties": { + "param2": { + "type": "string" + } + } + } + ] + }, + "encoding": { + "param2": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "SwaggerIngoreAnnotatedType": { + "type": "object", + "properties": { + "NotIgnoredString": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet8_0.verified.txt index ce2208344a..09cd6845a7 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet8_0.verified.txt @@ -57,5 +57,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet9_0.verified.txt index ce2208344a..09cd6845a7 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_FromFormObject_AndString.DotNet9_0.verified.txt @@ -57,5 +57,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet10_0.verified.txt new file mode 100644 index 0000000000..dcb2bf290f --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet10_0.verified.txt @@ -0,0 +1,48 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "Fake" + ], + "parameters": [ + { + "name": "param1", + "in": "query", + "schema": { + "$ref": "#/components/schemas/IntEnum" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "IntEnum": { + "enum": [ + 2, + 4, + 8 + ], + "type": "integer", + "format": "int32" + } + } + }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet8_0.verified.txt index 0eb507c649..dcb2bf290f 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet8_0.verified.txt @@ -39,5 +39,10 @@ "format": "int32" } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet9_0.verified.txt index 0eb507c649..dcb2bf290f 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.GetSwagger_Works_As_Expected_When_TypeIsEnum_AndModelMetadataTypeIsString.DotNet9_0.verified.txt @@ -39,5 +39,10 @@ "format": "int32" } } - } + }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithAcceptFromHeaderParameter.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithAcceptFromHeaderParameter.DotNet10_0.verified.txt new file mode 100644 index 0000000000..7e8db45714 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithAcceptFromHeaderParameter.DotNet10_0.verified.txt @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "get": { + "operationId": "OperationIdSetInMetadata", + "parameters": [ + { + "name": "accept" + }, + { + "name": "param", + "schema": { + "type": "string" + } + } + ], + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithAuthorizationFromHeaderParameter.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithAuthorizationFromHeaderParameter.DotNet10_0.verified.txt new file mode 100644 index 0000000000..ad0d5948d7 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithAuthorizationFromHeaderParameter.DotNet10_0.verified.txt @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "get": { + "operationId": "OperationIdSetInMetadata", + "parameters": [ + { + "name": "authorization" + }, + { + "name": "param", + "schema": { + "type": "string" + } + } + ], + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithContentTypeFromHeaderParameter.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithContentTypeFromHeaderParameter.DotNet10_0.verified.txt new file mode 100644 index 0000000000..53d0e30a9a --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.IllegalHeaderForOperation_action=ActionWithContentTypeFromHeaderParameter.DotNet10_0.verified.txt @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "get": { + "operationId": "OperationIdSetInMetadata", + "parameters": [ + { + "name": "Content-Type" + }, + { + "name": "param", + "schema": { + "type": "string" + } + } + ], + "responses": { } + } + } + }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.OperationHasSwaggerIgnoreAttribute.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.OperationHasSwaggerIgnoreAttribute.DotNet10_0.verified.txt new file mode 100644 index 0000000000..0e2c5aacab --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.OperationHasSwaggerIgnoreAttribute.DotNet10_0.verified.txt @@ -0,0 +1,9 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { }, + "components": { } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet10_0.verified.txt new file mode 100644 index 0000000000..48ec45c64a --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet10_0.verified.txt @@ -0,0 +1,51 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource1": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/resource2": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/resource3": { + "post": { + "tags": [ + "Fake" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet8_0.verified.txt index cc883c410c..48ec45c64a 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet8_0.verified.txt @@ -42,5 +42,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet9_0.verified.txt index cc883c410c..48ec45c64a 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.SortKeySelectorIsSpecified.DotNet9_0.verified.txt @@ -42,5 +42,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "Fake" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet10_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet10_0.verified.txt new file mode 100644 index 0000000000..a007011e63 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet10_0.verified.txt @@ -0,0 +1,27 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "Test API", + "version": "V1" + }, + "paths": { + "/resource": { + "post": { + "tags": [ + "resource" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { }, + "tags": [ + { + "name": "resource" + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet8_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet8_0.verified.txt index 26ccf63f38..a007011e63 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet8_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet8_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "resource" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet9_0.verified.txt b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet9_0.verified.txt index 26ccf63f38..a007011e63 100644 --- a/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet9_0.verified.txt +++ b/test/Swashbuckle.AspNetCore.SwaggerGen.Test/snapshots/VerifyTests.TagSelectorIsSpecified.DotNet9_0.verified.txt @@ -18,5 +18,10 @@ } } }, - "components": { } + "components": { }, + "tags": [ + { + "name": "resource" + } + ] } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.TestSupport/Extensions/IOpenApiAnyExtensions.cs b/test/Swashbuckle.AspNetCore.TestSupport/Extensions/JsonNodeExtensionExtensions.cs similarity index 61% rename from test/Swashbuckle.AspNetCore.TestSupport/Extensions/IOpenApiAnyExtensions.cs rename to test/Swashbuckle.AspNetCore.TestSupport/Extensions/JsonNodeExtensionExtensions.cs index 8ee45287e7..ce37f7fb67 100644 --- a/test/Swashbuckle.AspNetCore.TestSupport/Extensions/IOpenApiAnyExtensions.cs +++ b/test/Swashbuckle.AspNetCore.TestSupport/Extensions/JsonNodeExtensionExtensions.cs @@ -1,17 +1,15 @@ using Microsoft.OpenApi; -using Microsoft.OpenApi.Writers; - -using Any = Microsoft.OpenApi.Any.IOpenApiAny; namespace Swashbuckle.AspNetCore.TestSupport; -public static class IOpenApiAnyExtensions +public static class JsonNodeExtensionExtensions { - public static string ToJson(this Any openApiAny) + public static string ToJson(this JsonNodeExtension openApiAny) { var stringWriter = new StringWriter(); var jsonWriter = new OpenApiJsonWriter(stringWriter); + // Use 3.0 for consistency with previous versions of Microsoft.OpenApi openApiAny.Write(jsonWriter, OpenApiSpecVersion.OpenApi3_0); return stringWriter.ToString(); diff --git a/test/WebSites/Basic/Controllers/CrudActionsController.cs b/test/WebSites/Basic/Controllers/CrudActionsController.cs index 0735ed892b..a143e53458 100644 --- a/test/WebSites/Basic/Controllers/CrudActionsController.cs +++ b/test/WebSites/Basic/Controllers/CrudActionsController.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.Diagnostics; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; namespace Basic.Controllers; @@ -27,10 +28,17 @@ public class CrudActionsController /// /// [HttpPost(Name = "CreateProduct")] +#if NET10_0_OR_GREATER + public Ok Create([FromBody, Required] Product product) + { + return TypedResults.Ok(product); + } +#else public Product Create([FromBody, Required] Product product) { return product; } +#endif /// Get all products /// diff --git a/test/WebSites/Basic/Startup.cs b/test/WebSites/Basic/Startup.cs index ba8ce11df0..221a801a32 100644 --- a/test/WebSites/Basic/Startup.cs +++ b/test/WebSites/Basic/Startup.cs @@ -2,7 +2,7 @@ using System.Reflection; using Basic.Swagger; using Microsoft.AspNetCore.Localization; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace Basic; @@ -61,7 +61,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) endpoints.MapSwagger("swagger/{documentName}/swagger.json"); endpoints.MapSwagger("swagger/{documentName}/swaggerv2.json", c => { - c.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0; + c.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0; + }); + endpoints.MapSwagger("swagger/{documentName}/swaggerv3_1.json", c => + { + c.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1; }); }); diff --git a/test/WebSites/Basic/Swagger/AddCartsByIdGetExternalDocs.cs b/test/WebSites/Basic/Swagger/AddCartsByIdGetExternalDocs.cs index 94e389c07a..b4ed94831e 100644 --- a/test/WebSites/Basic/Swagger/AddCartsByIdGetExternalDocs.cs +++ b/test/WebSites/Basic/Swagger/AddCartsByIdGetExternalDocs.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Basic.Swagger; diff --git a/test/WebSites/Basic/Swagger/AssignOperationVendorExtensions.cs b/test/WebSites/Basic/Swagger/AssignOperationVendorExtensions.cs index ee0c48bba5..300f8eb731 100644 --- a/test/WebSites/Basic/Swagger/AssignOperationVendorExtensions.cs +++ b/test/WebSites/Basic/Swagger/AssignOperationVendorExtensions.cs @@ -1,5 +1,4 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Basic.Swagger; @@ -8,6 +7,7 @@ public class AssignOperationVendorExtensions : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { - operation.Extensions.Add("x-purpose", new OpenApiString("test")); + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add("x-purpose", new JsonNodeExtension("test")); } } diff --git a/test/WebSites/Basic/Swagger/AssignRequestBodyVendorExtensions.cs b/test/WebSites/Basic/Swagger/AssignRequestBodyVendorExtensions.cs index b4243a40ee..e61b86f6d1 100644 --- a/test/WebSites/Basic/Swagger/AssignRequestBodyVendorExtensions.cs +++ b/test/WebSites/Basic/Swagger/AssignRequestBodyVendorExtensions.cs @@ -1,13 +1,16 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Basic.Swagger; public class AssignRequestBodyVendorExtensions : IRequestBodyFilter { - public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context) + public void Apply(IOpenApiRequestBody requestBody, RequestBodyFilterContext context) { - requestBody.Extensions.Add("x-purpose", new OpenApiString("test")); + if (requestBody is OpenApiRequestBody body) + { + body.Extensions ??= new Dictionary(); + body.Extensions.Add("x-purpose", new JsonNodeExtension("test")); + } } } diff --git a/test/WebSites/Basic/Swagger/ExamplesSchemaFilter.cs b/test/WebSites/Basic/Swagger/ExamplesSchemaFilter.cs index 5092ee5453..3d52ffb5b7 100644 --- a/test/WebSites/Basic/Swagger/ExamplesSchemaFilter.cs +++ b/test/WebSites/Basic/Swagger/ExamplesSchemaFilter.cs @@ -1,20 +1,25 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using System.Text.Json.Nodes; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Basic.Swagger; public class ExamplesSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { - schema.Example = context.Type.Name switch + if (schema is not OpenApiSchema concrete) { - "Product" => new OpenApiObject + return; + } + + concrete.Example = context.Type.Name switch + { + "Product" => new JsonObject { - ["id"] = new OpenApiInteger(123), - ["description"] = new OpenApiString("foobar"), - ["price"] = new OpenApiDouble(14.37) + ["id"] = 123, + ["description"] = "foobar", + ["price"] = 14.37d }, _ => null, }; diff --git a/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net10.0.json b/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net10.0.json new file mode 100644 index 0000000000..91a88cd8d1 --- /dev/null +++ b/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net10.0.json @@ -0,0 +1,59 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "CliExample", + "version": "1.0" + }, + "servers": [ + { + "url": "http://localhost:51071" + } + ], + "paths": { + "/products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net8.0.json b/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net8.0.json index d5707c9824..91a88cd8d1 100644 --- a/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net8.0.json +++ b/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net8.0.json @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net9.0.json b/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net9.0.json index d5707c9824..91a88cd8d1 100644 --- a/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net9.0.json +++ b/test/WebSites/CliExample/wwwroot/swagger/v1/swagger_net9.0.json @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net10.0.json b/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net10.0.json new file mode 100644 index 0000000000..eeda72e5e4 --- /dev/null +++ b/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net10.0.json @@ -0,0 +1,59 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "CliExampleWithFactory", + "version": "1.0" + }, + "servers": [ + { + "url": "http://localhost:57556/" + } + ], + "paths": { + "/products": { + "get": { + "tags": [ + "Products" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Product": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + } + }, + "tags": [ + { + "name": "Products" + } + ] +} \ No newline at end of file diff --git a/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net8.0.json b/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net8.0.json index b2d3ff6db2..eeda72e5e4 100644 --- a/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net8.0.json +++ b/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net8.0.json @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net9.0.json b/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net9.0.json index b2d3ff6db2..eeda72e5e4 100644 --- a/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net9.0.json +++ b/test/WebSites/CliExampleWithFactory/wwwroot/swagger/v1/swagger_net9.0.json @@ -50,5 +50,10 @@ "additionalProperties": false } } - } + }, + "tags": [ + { + "name": "Products" + } + ] } \ No newline at end of file diff --git a/test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs b/test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs index 859b6c9952..8e93c7a124 100644 --- a/test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs +++ b/test/WebSites/CustomDocumentSerializer/DocumentSerializerTest.cs @@ -1,6 +1,4 @@ using Microsoft.OpenApi; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Writers; using Swashbuckle.AspNetCore.Swagger; namespace CustomDocumentSerializer; @@ -15,6 +13,7 @@ public void SerializeDocument(OpenApiDocument document, IOpenApiWriter writer, O { OpenApiSpecVersion.OpenApi2_0 => "DocumentSerializerTest2.0", OpenApiSpecVersion.OpenApi3_0 => "DocumentSerializerTest3.0", + OpenApiSpecVersion.OpenApi3_1 => "DocumentSerializerTest3.1", _ => throw new NotImplementedException() }; diff --git a/test/WebSites/CustomDocumentSerializer/Startup.cs b/test/WebSites/CustomDocumentSerializer/Startup.cs index 196d301c24..82471b8138 100644 --- a/test/WebSites/CustomDocumentSerializer/Startup.cs +++ b/test/WebSites/CustomDocumentSerializer/Startup.cs @@ -27,6 +27,7 @@ public void Configure(IApplicationBuilder app) endpoints.MapControllers(); endpoints.MapSwagger("swagger/{documentName}/swagger.json"); endpoints.MapSwagger("swagger/{documentName}/swaggerv2.json", c => c.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0); + endpoints.MapSwagger("swagger/{documentName}/swaggerv3_1.json", c => c.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_1); }); } } diff --git a/test/WebSites/DocumentationSnippets/AuthResponsesOperationFilter.cs b/test/WebSites/DocumentationSnippets/AuthResponsesOperationFilter.cs index 166d338c93..63e199d152 100644 --- a/test/WebSites/DocumentationSnippets/AuthResponsesOperationFilter.cs +++ b/test/WebSites/DocumentationSnippets/AuthResponsesOperationFilter.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Authorization; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace DocumentationSnippets; diff --git a/test/WebSites/DocumentationSnippets/AutoRestSchemaFilter.cs b/test/WebSites/DocumentationSnippets/AutoRestSchemaFilter.cs index 4497d60d75..5aec7d5bd1 100644 --- a/test/WebSites/DocumentationSnippets/AutoRestSchemaFilter.cs +++ b/test/WebSites/DocumentationSnippets/AutoRestSchemaFilter.cs @@ -1,5 +1,5 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using System.Text.Json.Nodes; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace DocumentationSnippets; @@ -7,18 +7,21 @@ namespace DocumentationSnippets; // begin-snippet: SwaggerGen-AutoRestSchemaFilter public class AutoRestSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { var type = context.Type; - if (type.IsEnum) + if (type.IsEnum && schema is OpenApiSchema concrete) { - schema.Extensions.Add( + concrete.Extensions ??= new Dictionary(); + concrete.Extensions.Add( "x-ms-enum", - new OpenApiObject - { - ["name"] = new OpenApiString(type.Name), - ["modelAsString"] = new OpenApiBoolean(true) - } + new JsonNodeExtension( + new JsonObject + { + ["name"] = type.Name, + ["modelAsString"] = true + } + ) ); } } diff --git a/test/WebSites/DocumentationSnippets/CustomDocumentSerializer.cs b/test/WebSites/DocumentationSnippets/CustomDocumentSerializer.cs index 3e85090f3c..ea7d3fc760 100644 --- a/test/WebSites/DocumentationSnippets/CustomDocumentSerializer.cs +++ b/test/WebSites/DocumentationSnippets/CustomDocumentSerializer.cs @@ -1,6 +1,4 @@ using Microsoft.OpenApi; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Writers; using Swashbuckle.AspNetCore.Swagger; namespace DocumentationSnippets; diff --git a/test/WebSites/DocumentationSnippets/DictionaryTKeyEnumTValueSchemaFilter.cs b/test/WebSites/DocumentationSnippets/DictionaryTKeyEnumTValueSchemaFilter.cs index 08345f37a2..2c85551838 100644 --- a/test/WebSites/DocumentationSnippets/DictionaryTKeyEnumTValueSchemaFilter.cs +++ b/test/WebSites/DocumentationSnippets/DictionaryTKeyEnumTValueSchemaFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace DocumentationSnippets; @@ -6,8 +6,13 @@ namespace DocumentationSnippets; // begin-snippet: SwaggerGen-DictionaryTKeyEnumTValueSchemaFilter public class DictionaryTKeyEnumTValueSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { + if (schema is not OpenApiSchema concrete) + { + return; + } + // Only run for fields that are a Dictionary if (!context.Type.IsGenericType || !context.Type.GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>))) { @@ -23,8 +28,8 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context) return; } - schema.Type = "object"; - schema.Properties = keyType.GetEnumNames().ToDictionary( + concrete.Type = JsonSchemaType.Object; + concrete.Properties = keyType.GetEnumNames().ToDictionary( name => name, name => context.SchemaGenerator.GenerateSchema(valueType, context.SchemaRepository)); } diff --git a/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs b/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs index 1cbb116eb9..febdaab384 100644 --- a/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs +++ b/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs @@ -1,5 +1,5 @@ using System.Reflection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace DocumentationSnippets; @@ -159,7 +159,7 @@ public static void Configure(this IServiceCollection services) // begin-snippet: SwaggerGen-CustomSchemaMapping services.AddSwaggerGen(options => { - options.MapType(() => new OpenApiSchema { Type = "string" }); + options.MapType(() => new OpenApiSchema { Type = JsonSchemaType.String }); }); // end-snippet @@ -213,15 +213,9 @@ public static void Configure(this IServiceCollection services) // begin-snippet: SwaggerGen-AddSecurityRequirement services.AddSwaggerGen(options => { - options.AddSecurityRequirement(new OpenApiSecurityRequirement + options.AddSecurityRequirement((document) => new OpenApiSecurityRequirement() { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } - }, - ["readAccess", "writeAccess"] - } + [new OpenApiSecuritySchemeReference("oauth2", document)] = ["readAccess", "writeAccess"] }); }); // end-snippet @@ -236,15 +230,9 @@ public static void Configure(this IServiceCollection services) BearerFormat = "JWT", Description = "JWT Authorization header using the Bearer scheme." }); - options.AddSecurityRequirement(new OpenApiSecurityRequirement + options.AddSecurityRequirement(document => new OpenApiSecurityRequirement { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" } - }, - [] - } + [new OpenApiSecuritySchemeReference("bearer", document)] = [] }); }); // end-snippet diff --git a/test/WebSites/DocumentationSnippets/ItemSchemaFilter.cs b/test/WebSites/DocumentationSnippets/ItemSchemaFilter.cs index 316c5729ee..dbb3c212cb 100644 --- a/test/WebSites/DocumentationSnippets/ItemSchemaFilter.cs +++ b/test/WebSites/DocumentationSnippets/ItemSchemaFilter.cs @@ -1,5 +1,5 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using System.Text.Json.Nodes; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace DocumentationSnippets; @@ -7,13 +7,16 @@ namespace DocumentationSnippets; // begin-snippet: Annotations-SchemaFilter public class ItemSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { - schema.Example = new OpenApiObject + if (schema is OpenApiSchema concrete) { - ["Id"] = new OpenApiInteger(1), - ["Description"] = new OpenApiString("An awesome item") - }; + concrete.Example = new JsonObject + { + ["Id"] = 1, + ["Description"] = "An awesome item" + }; + } } } // end-snippet diff --git a/test/WebSites/DocumentationSnippets/Program.cs b/test/WebSites/DocumentationSnippets/Program.cs index 340d5ce89d..3bc15b890c 100644 --- a/test/WebSites/DocumentationSnippets/Program.cs +++ b/test/WebSites/DocumentationSnippets/Program.cs @@ -1,5 +1,5 @@ // begin-snippet: README-configure -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; var builder = WebApplication.CreateBuilder(args); diff --git a/test/WebSites/DocumentationSnippets/SecurityRequirementsOperationFilter.cs b/test/WebSites/DocumentationSnippets/SecurityRequirementsOperationFilter.cs index 6e5bc21460..e939ccda0c 100644 --- a/test/WebSites/DocumentationSnippets/SecurityRequirementsOperationFilter.cs +++ b/test/WebSites/DocumentationSnippets/SecurityRequirementsOperationFilter.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Authorization; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace DocumentationSnippets; @@ -23,10 +23,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" }); - var scheme = new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } - }; + var scheme = new OpenApiSecuritySchemeReference("oauth2", context.Document); operation.Security = [ diff --git a/test/WebSites/DocumentationSnippets/TagDescriptionsDocumentFilter.cs b/test/WebSites/DocumentationSnippets/TagDescriptionsDocumentFilter.cs index c9d9806733..562b18759e 100644 --- a/test/WebSites/DocumentationSnippets/TagDescriptionsDocumentFilter.cs +++ b/test/WebSites/DocumentationSnippets/TagDescriptionsDocumentFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace DocumentationSnippets; @@ -8,11 +8,11 @@ public class TagDescriptionsDocumentFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { - swaggerDoc.Tags = - [ - new OpenApiTag { Name = "Products", Description = "Browse/manage the product catalog" }, - new OpenApiTag { Name = "Orders", Description = "Submit orders" } - ]; + swaggerDoc.Tags = new HashSet() + { + new() { Name = "Products", Description = "Browse/manage the product catalog" }, + new() { Name = "Orders", Description = "Submit orders" } + }; } } // end-snippet diff --git a/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs b/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs index 3181fe7b13..8e096e4fef 100644 --- a/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs +++ b/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.OpenApi; -using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerUI; namespace DocumentationSnippets; @@ -216,6 +215,13 @@ public static void Configure(WebApplication app) }); // end-snippet + // begin-snippet: Swagger-OpenAPI3.1 + app.UseSwagger(options => + { + options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1; + }); + // end-snippet + // begin-snippet: Swagger-Swagger2.0 app.UseSwagger(options => { diff --git a/test/WebSites/GenericControllers/Startup.cs b/test/WebSites/GenericControllers/Startup.cs index 4a1871740a..23eff3af3a 100644 --- a/test/WebSites/GenericControllers/Startup.cs +++ b/test/WebSites/GenericControllers/Startup.cs @@ -1,5 +1,5 @@ using System.Reflection; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; namespace GenericControllers; diff --git a/test/WebSites/GenericControllers/Swagger/ApplySummariesOperationFilter.cs b/test/WebSites/GenericControllers/Swagger/ApplySummariesOperationFilter.cs index 9236b076fd..2cbc4ae3bc 100644 --- a/test/WebSites/GenericControllers/Swagger/ApplySummariesOperationFilter.cs +++ b/test/WebSites/GenericControllers/Swagger/ApplySummariesOperationFilter.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace GenericControllers.Swagger; diff --git a/test/WebSites/MultipleVersions/ConfigureSwaggerGenOptions.cs b/test/WebSites/MultipleVersions/ConfigureSwaggerGenOptions.cs index 01af933c06..d7900570e5 100644 --- a/test/WebSites/MultipleVersions/ConfigureSwaggerGenOptions.cs +++ b/test/WebSites/MultipleVersions/ConfigureSwaggerGenOptions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace MultipleVersions; diff --git a/test/WebSites/MvcWithNullable/MvcWithNullable.csproj b/test/WebSites/MvcWithNullable/MvcWithNullable.csproj index f4465a728b..80a6a0d685 100644 --- a/test/WebSites/MvcWithNullable/MvcWithNullable.csproj +++ b/test/WebSites/MvcWithNullable/MvcWithNullable.csproj @@ -13,12 +13,4 @@
- - - - - - - - diff --git a/test/WebSites/NswagClientExample/NswagClientExample.csproj b/test/WebSites/NswagClientExample/NswagClientExample.csproj index 5de3bfe65a..c4e3133343 100644 --- a/test/WebSites/NswagClientExample/NswagClientExample.csproj +++ b/test/WebSites/NswagClientExample/NswagClientExample.csproj @@ -5,6 +5,7 @@ $([System.IO.Path]::Combine('$(ArtifactsPath)', 'bin', 'Swashbuckle.AspNetCore.Cli', '$(Configuration.ToLower())_$(TargetFramework)')) <_NSwagTool>$(NSwagExe_Net80) <_NSwagTool Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net9.0'))">$(NSwagExe_Net90) + <_NSwagTool Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0'))">$(NSwagExe_Net100) diff --git a/test/WebSites/NswagClientExample/swagger_net10.0.json b/test/WebSites/NswagClientExample/swagger_net10.0.json new file mode 100644 index 0000000000..cc22ed49f6 --- /dev/null +++ b/test/WebSites/NswagClientExample/swagger_net10.0.json @@ -0,0 +1,479 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "NswagClientExample", + "version": "1.0" + }, + "servers": [ + { + "url": "http://example.com" + } + ], + "paths": { + "/Animals": { + "post": { + "tags": [ + "Animals" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/SecondLevel": { + "post": { + "tags": [ + "SecondLevel" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SubSubType" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SubSubType" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SubSubType" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + } + } + }, + "/SystemTextJsonAnimals": { + "post": { + "tags": [ + "SystemTextJsonAnimals" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDog" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDog" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDog" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/SystemTextJsonDefaultDiscriminatorAnimals": { + "post": { + "tags": [ + "SystemTextJsonDefaultDiscriminatorAnimals" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat" + }, + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Animal": { + "required": [ + "animalType" + ], + "type": "object", + "properties": { + "animalType": { + "$ref": "#/components/schemas/AnimalType" + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "animalType", + "mapping": { + "Cat": "#/components/schemas/Cat", + "Dog": "#/components/schemas/Dog" + } + } + }, + "AnimalType": { + "enum": [ + "Cat", + "Dog" + ], + "type": "string" + }, + "BaseType": { + "required": [ + "discriminator" + ], + "type": "object", + "properties": { + "discriminator": { + "type": "string" + }, + "property": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "discriminator", + "mapping": { + "SubSubType": "#/components/schemas/SubSubType" + } + } + }, + "Cat": { + "allOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "catSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "Dog": { + "allOf": [ + { + "$ref": "#/components/schemas/Animal" + }, + { + "type": "object", + "properties": { + "dogSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SubSubType": { + "allOf": [ + { + "$ref": "#/components/schemas/BaseType" + }, + { + "type": "object", + "properties": { + "property2": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonAnimal": { + "required": [ + "animalType" + ], + "type": "object", + "properties": { + "animalType": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "animalType", + "mapping": { + "Cat": "#/components/schemas/SystemTextJsonCat", + "Dog": "#/components/schemas/SystemTextJsonDog" + } + } + }, + "SystemTextJsonCat": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "type": "object", + "properties": { + "catSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonDefaultDiscriminatorAnimal": { + "required": [ + "$type" + ], + "type": "object", + "properties": { + "$type": { + "type": "string" + }, + "animalType": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "$type", + "mapping": { + "Cat": "#/components/schemas/SystemTextJsonDefaultDiscriminatorCat", + "Dog": "#/components/schemas/SystemTextJsonDefaultDiscriminatorDog" + } + } + }, + "SystemTextJsonDefaultDiscriminatorCat": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "type": "object", + "properties": { + "catSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonDefaultDiscriminatorDog": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonDefaultDiscriminatorAnimal" + }, + { + "type": "object", + "properties": { + "dogSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + }, + "SystemTextJsonDog": { + "allOf": [ + { + "$ref": "#/components/schemas/SystemTextJsonAnimal" + }, + { + "type": "object", + "properties": { + "dogSpecificProperty": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ] + } + } + }, + "tags": [ + { + "name": "Animals" + }, + { + "name": "SecondLevel" + }, + { + "name": "SystemTextJsonAnimals" + }, + { + "name": "SystemTextJsonDefaultDiscriminatorAnimals" + } + ] +} \ No newline at end of file diff --git a/test/WebSites/NswagClientExample/swagger_net8.0.json b/test/WebSites/NswagClientExample/swagger_net8.0.json index e65495816b..cc22ed49f6 100644 --- a/test/WebSites/NswagClientExample/swagger_net8.0.json +++ b/test/WebSites/NswagClientExample/swagger_net8.0.json @@ -461,5 +461,19 @@ ] } } - } + }, + "tags": [ + { + "name": "Animals" + }, + { + "name": "SecondLevel" + }, + { + "name": "SystemTextJsonAnimals" + }, + { + "name": "SystemTextJsonDefaultDiscriminatorAnimals" + } + ] } \ No newline at end of file diff --git a/test/WebSites/NswagClientExample/swagger_net9.0.json b/test/WebSites/NswagClientExample/swagger_net9.0.json index e65495816b..cc22ed49f6 100644 --- a/test/WebSites/NswagClientExample/swagger_net9.0.json +++ b/test/WebSites/NswagClientExample/swagger_net9.0.json @@ -461,5 +461,19 @@ ] } } - } + }, + "tags": [ + { + "name": "Animals" + }, + { + "name": "SecondLevel" + }, + { + "name": "SystemTextJsonAnimals" + }, + { + "name": "SystemTextJsonDefaultDiscriminatorAnimals" + } + ] } \ No newline at end of file diff --git a/test/WebSites/OAuth2Integration/OAuth2Integration.csproj b/test/WebSites/OAuth2Integration/OAuth2Integration.csproj index 52db6fe4a1..292e759632 100644 --- a/test/WebSites/OAuth2Integration/OAuth2Integration.csproj +++ b/test/WebSites/OAuth2Integration/OAuth2Integration.csproj @@ -10,14 +10,20 @@ - - + + + + + - - + + + + + diff --git a/test/WebSites/OAuth2Integration/ResourceServer/Swagger/SecurityRequirementsOperationFilter.cs b/test/WebSites/OAuth2Integration/ResourceServer/Swagger/SecurityRequirementsOperationFilter.cs index 86625a0c14..38b80f4c65 100644 --- a/test/WebSites/OAuth2Integration/ResourceServer/Swagger/SecurityRequirementsOperationFilter.cs +++ b/test/WebSites/OAuth2Integration/ResourceServer/Swagger/SecurityRequirementsOperationFilter.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization.Infrastructure; using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace OAuth2Integration.ResourceServer.Swagger; @@ -40,16 +40,13 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" }); - var oAuthScheme = new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } - }; + var scheme = new OpenApiSecuritySchemeReference("oauth2", context.Document); operation.Security = [ new OpenApiSecurityRequirement { - [oAuthScheme] = requiredScopes + [scheme] = requiredScopes } ]; } diff --git a/test/WebSites/OAuth2Integration/Startup.cs b/test/WebSites/OAuth2Integration/Startup.cs index 2353899018..1983494958 100644 --- a/test/WebSites/OAuth2Integration/Startup.cs +++ b/test/WebSites/OAuth2Integration/Startup.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using OAuth2Integration.ResourceServer.Swagger; namespace OAuth2Integration; @@ -69,13 +69,10 @@ public void ConfigureServices(IServiceCollection services) } }); - c.AddSecurityRequirement(new OpenApiSecurityRequirement + c.AddSecurityRequirement((document) => new OpenApiSecurityRequirement { { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } - }, + new OpenApiSecuritySchemeReference("oauth2", document), ["readAccess", "writeAccess"] } }); diff --git a/test/WebSites/TestFirst.IntegrationTests/ApiTestsSetup.cs b/test/WebSites/TestFirst.IntegrationTests/ApiTestsSetup.cs index 2dcbfcea93..68045c8d5d 100644 --- a/test/WebSites/TestFirst.IntegrationTests/ApiTestsSetup.cs +++ b/test/WebSites/TestFirst.IntegrationTests/ApiTestsSetup.cs @@ -1,4 +1,4 @@ -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.ApiTesting; using Xunit; diff --git a/test/WebSites/TestFirst.IntegrationTests/CreateUserTests.cs b/test/WebSites/TestFirst.IntegrationTests/CreateUserTests.cs index a6da6e08fd..8daf39da24 100644 --- a/test/WebSites/TestFirst.IntegrationTests/CreateUserTests.cs +++ b/test/WebSites/TestFirst.IntegrationTests/CreateUserTests.cs @@ -1,6 +1,6 @@ using System.Text; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Newtonsoft.Json; using Swashbuckle.AspNetCore; using Swashbuckle.AspNetCore.ApiTesting.Xunit; @@ -15,7 +15,7 @@ public CreateUserTests( WebApplicationFactory webApplicationFactory) : base(apiTestRunner, webApplicationFactory, "v1-generated") { - Describe("/api/users", OperationType.Post, new OpenApiOperation + Describe("/api/users", HttpMethod.Post, new OpenApiOperation { OperationId = "CreateUser", RequestBody = new OpenApiRequestBody @@ -27,12 +27,12 @@ public CreateUserTests( Schema = new OpenApiSchema { Type = JsonSchemaTypes.Object, - Properties = new Dictionary + Properties = new Dictionary { [ "email" ] = new OpenApiSchema { Type = JsonSchemaTypes.String }, [ "password" ] = new OpenApiSchema { Type = JsonSchemaTypes.String }, }, - Required = new SortedSet { "email", "password" } + Required = new SortedSet { "email", "password" }, } } }, @@ -43,7 +43,7 @@ public CreateUserTests( [ "201" ] = new OpenApiResponse { Description = "User created", - Headers = new Dictionary + Headers = new Dictionary { [ "Location" ] = new OpenApiHeader { diff --git a/test/WebSites/WebApi.Aot/Program.cs b/test/WebSites/WebApi.Aot/Program.cs index 31f22d2cab..57c0864b56 100644 --- a/test/WebSites/WebApi.Aot/Program.cs +++ b/test/WebSites/WebApi.Aot/Program.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; using Microsoft.AspNetCore.Routing.Constraints; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; var builder = WebApplication.CreateSlimBuilder(args); diff --git a/test/WebSites/WebApi/EndPoints/OpenApiEndpoints.cs b/test/WebSites/WebApi/EndPoints/OpenApiEndpoints.cs index 04d3a629d5..c8a776a460 100644 --- a/test/WebSites/WebApi/EndPoints/OpenApiEndpoints.cs +++ b/test/WebSites/WebApi/EndPoints/OpenApiEndpoints.cs @@ -43,57 +43,47 @@ public static IEndpointRouteBuilder MapWithOpenApiEndpoints(this IEndpointRouteB )) .ToArray(); }) - .WithName("GetWeatherForecast") - .WithOpenApi(); + .WithName("GetWeatherForecast"); group.MapPost("/multipleForms", ([FromForm] Person person, [FromForm] Address address) => { return $"{person} {address}"; - }) - .WithOpenApi(); + }); group.MapPost("/IFromFile", (IFormFile file, string queryParameter) => { return $"{file.FileName}{queryParameter}"; - }).WithOpenApi(o => - { - var parameter = o.Parameters?.FirstOrDefault(p => string.Equals(p.Name, "queryParameter", StringComparison.OrdinalIgnoreCase)); - if (parameter is not null) - { - parameter.Description = $"{parameter.Name} Description"; - } - return o; }); group.MapPost("/IFromFileCollection", (IFormFileCollection collection) => { return $"{collection.Count} {string.Join(',', collection.Select(f => f.FileName))}"; - }).WithOpenApi(); + }); group.MapPost("/IFromBody", (OrganizationCustomExchangeRatesDto dto) => { return $"{dto}"; - }).WithOpenApi(); + }); group.MapPost("/IFromFileAndString", (IFormFile file, [FromForm] string tags) => { return $"{file.FileName}{tags}"; - }).WithOpenApi(); + }); group.MapPost("/IFromFileAndEnum", (IFormFile file, [FromForm] DateTimeKind dateTimeKind) => { return $"{file.FileName}{dateTimeKind}"; - }).WithOpenApi(); + }); group.MapPost("/IFromObjectAndString", ([FromForm] Person person, [FromForm] string tags) => { return $"{person}{tags}"; - }).WithOpenApi(); + }); app.MapGet("/TypeWithTryParse/{tryParse}", (TypeWithTryParse tryParse) => { return tryParse.Name; - }).WithOpenApi(); + }); return app; } diff --git a/test/WebSites/WebApi/EndPoints/SwaggerAnnotationsEndpoints.cs b/test/WebSites/WebApi/EndPoints/SwaggerAnnotationsEndpoints.cs index 05fe9c001e..7e0c02b2aa 100644 --- a/test/WebSites/WebApi/EndPoints/SwaggerAnnotationsEndpoints.cs +++ b/test/WebSites/WebApi/EndPoints/SwaggerAnnotationsEndpoints.cs @@ -17,8 +17,7 @@ public static IEndpointRouteBuilder MapAnnotationsEndpoints(this IEndpointRouteB .WithTags("Annotations") .DisableAntiforgery(); - group.MapPost("/fruit/{id}", CreateFruit) - .WithOpenApi(); + group.MapPost("/fruit/{id}", CreateFruit); group.MapPost("/singleForm", ([FromForm] PersonAnnotated person) => { diff --git a/test/WebSites/WebApi/EndPoints/XmlCommentsEndpoints.cs b/test/WebSites/WebApi/EndPoints/XmlCommentsEndpoints.cs index e5e93a9d96..0e35fca1cd 100644 --- a/test/WebSites/WebApi/EndPoints/XmlCommentsEndpoints.cs +++ b/test/WebSites/WebApi/EndPoints/XmlCommentsEndpoints.cs @@ -1,4 +1,8 @@ -namespace WebApi.EndPoints; +#if NET10_0_OR_GREATER +using Microsoft.AspNetCore.Mvc; +#endif + +namespace WebApi.EndPoints; /// /// Class of Extensions to add XmlEndpoints @@ -14,6 +18,12 @@ public static IEndpointRouteBuilder MapXmlCommentsEndpoints(this IEndpointRouteB group.MapGet("/Car/{id}", GetProduct); +#if NET10_0_OR_GREATER + group.MapGet("Car", GetProductAsParameters); + group.MapGet("CarWithProduces",GetProductWithProduces); + group.MapGet("CarWithProducesDefaultResponseType",GetProductProducesDefaultResponseType); +#endif + return app; } /// @@ -23,6 +33,29 @@ public static IEndpointRouteBuilder MapXmlCommentsEndpoints(this IEndpointRouteB /// A Product Id private static Product GetProduct(int id) => new() { Id = id, Description = "A product" }; + +#if NET10_0_OR_GREATER + /// + /// Returns a specific product using asParameters record + /// + [ProducesResponseType(typeof(Product), 200, Description = "A Product")] + private static Product GetProductAsParameters([AsParameters] Product productAsParameters) + => productAsParameters; + + /// + /// Returns a specific product With Produces attribute + /// + [Produces(typeof(Product), Description = "A Product")] + private static Product GetProductWithProduces(int id) + => new() { Id = id, Description = "A product" }; + + /// + /// Returns a specific product With ProducesDefaultResponseType attribute + /// + [ProducesDefaultResponseType(typeof(Product), Description = "A Product")] + private static Product GetProductProducesDefaultResponseType(int id) + => new() { Id = id, Description = "A product" }; +#endif } /// diff --git a/test/WebSites/WebApi/WebApi.csproj b/test/WebSites/WebApi/WebApi.csproj index c509238d96..86cbcaf1fd 100644 --- a/test/WebSites/WebApi/WebApi.csproj +++ b/test/WebSites/WebApi/WebApi.csproj @@ -14,12 +14,4 @@ - - - - - - - -