## File: README.md

# Swashbuckle.AspNetCore

[![NuGet][package-badge-version]][package-download]
[![NuGet Downloads][package-badge-downloads]][package-download]

[![Build status][build-badge]][build-status]
[![Code coverage][coverage-badge]][coverage-report]
[![OpenSSF Scorecard][scorecard-badge]][scorecard-report]

[![Help Wanted][help-wanted-badge]][help-wanted-issues]

[OpenAPI][swagger] (Swagger) tooling for APIs built with ASP.NET Core.

Generate beautiful API documentation, including a UI to explore and test operations, directly from your application code.

In addition to its [Swagger 2.0 and OpenAPI 3.0/3.1][swagger-specification] generator, Swashbuckle.AspNetCore also provides
an embedded version of the awesome [swagger-ui][swagger-ui] project that's powered by the generated OpenAPI JSON documents.
This means you can complement your API with living documentation that's always in sync with the latest code. Best of all, it
requires minimal coding and maintenance, allowing you to focus on building an awesome API.

But that's not all!

Once you have an API that can describe itself with a OpenAPI document, you've opened the treasure chest of OpenAPI-based
tools including a client generator that can be targeted to a wide range of popular platforms. See [swagger-codegen][swagger-codegen]
for more details.

> [!IMPORTANT]  
> Version 10.0 of Swashbuckle.AspNetCore introduces breaking changes due to upgrading our dependency on [Microsoft.OpenApi][microsoft-openapi]
> to version 2.x.x to add support for generating OpenAPI 3.1 documents. Please see _[Migrating to Swashbuckle.AspNetCore v10][v10-migration]_ for more details.

## Compatibility

| **Swashbuckle Version**                                                                                          | **ASP.NET Core**           | **OpenAPI/Swagger Versions** | **Microsoft.OpenApi**                                                                        | **swagger-ui**                                                                            | **Redoc**                                                                    |
|:-----------------------------------------------------------------------------------------------------------------|:---------------------------|:-----------------------------|:---------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------|
| [![CI Swashbuckle.AspNetCore version][swashbuckle-version-vnext-badge]][swashbuckle-version-vnext-release]       | >= 8.0.0                   | 3.1, **3.0**, 2.0            | [![Microsoft.OpenApi version][openapi-version-vnext-badge]][openapi-version-vnext-release]   | [![swagger-ui version][swaggerui-version-vnext-badge]][swaggerui-version-vnext-release]   | [![Redoc version][redoc-version-vnext-badge]][redoc-version-vnext-release]   |
| [![Latest Swashbuckle.AspNetCore version][swashbuckle-version-latest-badge]][swashbuckle-version-latest-release] | >= 8.0.0                   | 3.1, **3.0**, 2.0            | [![Microsoft.OpenApi version][openapi-version-latest-badge]][openapi-version-latest-release] | [![swagger-ui version][swaggerui-version-latest-badge]][swaggerui-version-latest-release] | [![Redoc version][redoc-version-latest-badge]][redoc-version-latest-release] |
| [![Last v9 Swashbuckle.AspNetCore version][swashbuckle-version-v9-badge]][swashbuckle-version-v9-release]        | 9.0.x, 8.0.x               | **3.0**, 2.0                 | [![Microsoft.OpenApi version][openapi-version-v9-badge]][openapi-version-v9-release]         | [![swagger-ui version][swaggerui-version-v9-badge]][swaggerui-version-v9-release]         | [![Redoc version][redoc-version-v9-badge]][redoc-version-v9-release]         |
| [![Last v8 Swashbuckle.AspNetCore version][swashbuckle-version-v8-badge]][swashbuckle-version-v8-release]        | 9.0.x, 8.0.x, 2.3.x        | **3.0**, 2.0                 | [![Microsoft.OpenApi version][openapi-version-v8-badge]][openapi-version-v8-release]         | [![swagger-ui version][swaggerui-version-v8-badge]][swaggerui-version-v8-release]         | [![Redoc version][redoc-version-v8-badge]][redoc-version-v8-release]         |

[swashbuckle-version-vnext-badge]: https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2FHEAD%2FDirectory.Build.props&query=(%2F%2FProject%2FPropertyGroup%2FVersionPrefix)%5B1%5D&prefix=v&suffix=-*&logo=github&label=CI
[swashbuckle-version-vnext-release]: https://www.myget.org/gallery/domaindrivendev
[swashbuckle-version-latest-badge]: https://img.shields.io/github/v/release/domaindrivendev/Swashbuckle.AspNetCore?display_name=tag&logo=github&label=v10
[swashbuckle-version-latest-release]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases/latest
[swashbuckle-version-v9-badge]: https://img.shields.io/badge/v9-v9.0.6-blue?logo=github
[swashbuckle-version-v9-release]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases/tag/v9.0.6
[swashbuckle-version-v8-badge]: https://img.shields.io/badge/v8-v8.1.4-blue?logo=github
[swashbuckle-version-v8-release]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases/tag/v8.1.4

[openapi-version-vnext-badge]: https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2FHEAD%2Fsrc%2FSwashbuckle.AspNetCore.Swagger%2FSwashbuckle.AspNetCore.Swagger.csproj&query=%2F%2FPackageReference%5B%40Include%3D'Microsoft.OpenApi'%5D%2F%40VersionOverride&logo=openapiinitiative&label=Microsoft.OpenApi
[openapi-version-vnext-release]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/HEAD/src/Swashbuckle.AspNetCore.Swagger/Swashbuckle.AspNetCore.Swagger.csproj#L20
[openapi-version-latest-badge]: https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv10.2.3%2Fsrc%2FSwashbuckle.AspNetCore.Swagger%2FSwashbuckle.AspNetCore.Swagger.csproj&query=%2F%2FPackageReference%5B%40Include%3D'Microsoft.OpenApi'%5D%2F%40VersionOverride&logo=openapiinitiative&label=Microsoft.OpenApi
[openapi-version-latest-release]: https://github.com/microsoft/OpenAPI.NET/releases/tag/v2.7.5
[openapi-version-v9-badge]: https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv9.0.6%2FDirectory.Packages.props&query=%2F%2FPackageVersion%5B%40Include%3D'Microsoft.OpenApi'%5D%2F%40Version&logo=openapiinitiative&label=Microsoft.OpenApi
[openapi-version-v9-release]: https://github.com/microsoft/OpenAPI.NET/releases/tag/v1.6.25
[openapi-version-v8-badge]: https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv8.1.4%2FDirectory.Packages.props&query=%2F%2FPackageVersion%5B%40Include%3D'Microsoft.OpenApi'%5D%2F%40Version&logo=openapiinitiative&label=Microsoft.OpenApi
[openapi-version-v8-release]: https://github.com/microsoft/OpenAPI.NET/releases/tag/1.6.23

[swaggerui-version-vnext-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2FHEAD%2Fsrc%2FSwashbuckle.AspNetCore.SwaggerUI%2Fpackage.json&query=%24.dependencies.swagger-ui-dist&style=flat&label=swagger-ui
[swaggerui-version-vnext-release]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/HEAD/src/Swashbuckle.AspNetCore.SwaggerUI/package.json#L6
[swaggerui-version-latest-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv10.2.3%2Fsrc%2FSwashbuckle.AspNetCore.SwaggerUI%2Fpackage.json&query=%24.dependencies.swagger-ui-dist&style=flat&label=swagger-ui
[swaggerui-version-latest-release]: https://github.com/swagger-api/swagger-ui/releases/tag/v5.32.6
[swaggerui-version-v9-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv9.0.6%2Fsrc%2FSwashbuckle.AspNetCore.SwaggerUI%2Fpackage.json&query=%24.dependencies.swagger-ui-dist&style=flat&label=swagger-ui
[swaggerui-version-v9-release]: https://github.com/swagger-api/swagger-ui/releases/tag/v5.29.2
[swaggerui-version-v8-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv8.1.4%2Fsrc%2FSwashbuckle.AspNetCore.SwaggerUI%2Fpackage.json&query=%24.dependencies.swagger-ui-dist&style=flat&label=swagger-ui
[swaggerui-version-v8-release]: https://github.com/swagger-api/swagger-ui/releases/tag/v5.22.0

[redoc-version-vnext-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2FHEAD%2Fsrc%2FSwashbuckle.AspNetCore.ReDoc%2Fpackage.json&query=%24.dependencies.redoc&style=flat&label=Redoc
[redoc-version-vnext-release]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/HEAD/src/Swashbuckle.AspNetCore.ReDoc/package.json#L6
[redoc-version-latest-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv10.2.3%2Fsrc%2FSwashbuckle.AspNetCore.ReDoc%2Fpackage.json&query=%24.dependencies.redoc&style=flat&label=Redoc
[redoc-version-latest-release]: https://github.com/Redocly/redoc/releases/tag/v2.5.3
[redoc-version-v9-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv9.0.6%2Fsrc%2FSwashbuckle.AspNetCore.ReDoc%2Fpackage.json&query=%24.dependencies.redoc&style=flat&label=Redoc
[redoc-version-v9-release]: https://github.com/Redocly/redoc/releases/tag/v2.5.1
[redoc-version-v8-badge]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdomaindrivendev%2FSwashbuckle.AspNetCore%2Frefs%2Ftags%2Fv8.1.4%2Fsrc%2FSwashbuckle.AspNetCore.ReDoc%2Fpackage.json&query=%24.dependencies.redoc&style=flat&label=Redoc
[redoc-version-v8-release]: https://github.com/Redocly/redoc/releases/tag/v2.5.0

## Getting Started

First install the kitchen-sink NuGet package into your ASP.NET Core application:

```terminal
dotnet add package Swashbuckle.AspNetCore
```

Next, register the OpenAPI (Swagger) generator in your application's startup path, defining one or more OpenAPI documents. For example:



<a id='snippet-README-configure'></a>
```cs
using Microsoft.OpenApi;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddMvc();

builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});

var app = builder.Build();

app.UseSwagger();

app.Run();
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/Program.cs#L1-L18) | [anchor](#snippet-README-configure)</sup>




Ensure your API endpoints and any parameters are decorated with `[Http*]` and `[From*]` attributes, where appropriate.



<a id='snippet-README-endpoints'></a>
```cs
[HttpPost]
public void CreateProduct([FromBody] Product product)
{
    // Implementation goes here
}

[HttpGet]
public IEnumerable SearchProducts([FromQuery] string keywords)
{
    // Implementation goes here
    return [];
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L9-L22) | [anchor](#snippet-README-endpoints)</sup>



> [!NOTE]
> If you omit the explicit parameter bindings, the generator will describe them as "query" parameters by default.

Then, expose the OpenAPI JSON document endpoint(s) using one of following methods:

- Add endpoints if you're using endpoint-based routing:



<a id='snippet-README-MapSwagger'></a>
```cs
// Your own endpoints go here, and then...
app.MapSwagger();
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L10-L13) | [anchor](#snippet-README-MapSwagger)</sup>



- Adding the OpenAPI middleware:



<a id='snippet-README-UseSwagger'></a>
```cs
app.UseSwagger();
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L15-L17) | [anchor](#snippet-README-UseSwagger)</sup>



At this point, you can launch your application and view the generated OpenAPI document at `/swagger/v1/swagger.json`.

Finally, you can optionally add the [swagger-ui][swagger-ui] middleware to expose interactive documentation, specifying the OpenAPI document(s) to power it from:



<a id='snippet-README-UseSwaggerUI'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("v1/swagger.json", "My API V1");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L19-L24) | [anchor](#snippet-README-UseSwaggerUI)</sup>



Now you can restart your application and view the auto-generated, interactive documentation at `/swagger`.

## System.Text.Json (STJ) vs Newtonsoft.Json (Json.NET)

In versions of Swashbuckle.AspNetCore prior to `5.0.0`, Swashbuckle.AspNetCore would generate Schemas (descriptions of the data types exposed by an API) based
on the behavior of the [Newtonsoft.Json serializer][newtonsoft-json]. This made sense because that was the serializer that shipped with ASP.NET Core
at the time. However, since ASP.NET Core 3.0, ASP.NET Core introduces a new serializer, [System.Text.Json (STJ)][system-text-json] out-of-the-box.

If you want to use Newtonsoft.Json instead, you must install a separate package and explicitly opt-in. By default Swashbuckle.AspNetCore will assume
that you're using the System.Text.Json serializer and generate schemas based on its behavior. If you're using Newtonsoft.Json, then you'll need to install a
separate Swashbuckle.AspNetCore package, [Swashbuckle.AspNetCore.Newtonsoft][swashbuckle-aspnetcore-newtonsoft] to explicitly opt-in.

Below is an example of how to do this for ASP.NET Core MVC:

```terminal
dotnet add package Swashbuckle.AspNetCore.Newtonsoft
```



<a id='snippet-README-Newtonsoft.Json'></a>
```cs
services.AddMvc();

services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});

services.AddSwaggerGenNewtonsoftSupport();
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L11-L20) | [anchor](#snippet-README-Newtonsoft.Json)</sup>



## Swashbuckle, ApiExplorer, and Routing

Swashbuckle relies heavily on [`ApiExplorer`][api-explorer], the API metadata layer that ships with ASP.NET Core. If you're using the `AddMvc(...)`
helper methods to bootstrap the MVC stack, then API Explorer will be automatically registered and Swashbuckle.AspNetCore should work without issue.

However, if you're using `AddMvcCore(...)` for a more paired-down MVC stack, you'll need to explicitly add the API Explorer services:



<a id='snippet-README-MvcCore'></a>
```cs
services.AddMvcCore()
        .AddApiExplorer();
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L22-L25) | [anchor](#snippet-README-MvcCore)</sup>



Additionally, if you are using _[conventional routing][conventional-routing]_ (as opposed to attribute routing), any controllers and the actions on those
controllers that use conventional routing will not be represented in API Explorer, which means Swashbuckle won't be able to find those controllers and
generate OpenAPI operations for them.

For instance:



<a id='snippet-README-MvcConventionalRouting'></a>
```cs
app.UseMvc(routes =>
{
    // SwaggerGen won't find controllers that are routed via this technique.
    routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L26-L32) | [anchor](#snippet-README-MvcConventionalRouting)</sup>



You **must** use attribute routing for any controllers that you want represented in your OpenAPI document(s):



<a id='snippet-README-AttributeRouting'></a>
```cs
[Route("example")]
public class ExampleController : Controller
{
    [HttpGet("")]
    public IActionResult DoStuff()
    {
        // Your implementation
        return Empty;
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ExampleController.cs#L5-L16) | [anchor](#snippet-README-AttributeRouting)</sup>



Refer to the [ASP.NET Core MVC routing documentation][mvc-routing] for more information.

## Components

Swashbuckle.AspNetCore consists of multiple components that can be used together or individually depending on your needs.

At its core, there's an OpenAPI generator, middleware to expose OpenAPI (Swagger) documentation as JSON endpoints, and a
packaged version of the [swagger-ui][swagger-ui]. These three packages can be installed with the [`Swashbuckle.AspNetCore`][package-download]
_"metapackage"_ and will work together (see [Getting Started](#getting-started)) to provide API documentation that is automatically generated from your code.

Additionally, there are add-on packages (CLI tools, [an alternate UI using Redoc][redoc] etc.) that you can install and configure as needed.

### "Core" Packages

| **Package** | **NuGet** | **Description** |
| ----------- | --------- | --------------- |
| [Swashbuckle.AspNetCore.Swagger][swashbuckle-aspnetcore-swagger] | [][swashbuckle-aspnetcore-swagger] | Exposes OpenAPI JSON endpoints. It expects an implementation of `ISwaggerProvider` to be registered in the DI container, which it queries to retrieve `OpenApiDocument` instance(s) that are then exposed as serialized JSON. |
| [Swashbuckle.AspNetCore.SwaggerGen][swashbuckle-aspnetcore-swaggergen] | [][swashbuckle-aspnetcore-swaggergen] | Injects an implementation of `ISwaggerProvider` that can be used by the above component. This particular implementation generates `OpenApiDocument` instance(s) from your application endpoints (controllers, minimal endpoints etc.). |
| [Swashbuckle.AspNetCore.SwaggerUI][swashbuckle-aspnetcore-swaggerui] | [][swashbuckle-aspnetcore-swaggerui] | Exposes an embedded version of [swagger-ui][swagger-ui]. You specify the API endpoints where it can obtain OpenAPI documents from, and it uses them to power interactive documentation for your API. |

### Additional Packages

| **Package** | **NuGet** | **Description** |
| ----------- | --------- | --------------- |
| [Swashbuckle.AspNetCore.Annotations][swashbuckle-aspnetcore-annotations] | [][swashbuckle-aspnetcore-annotations] | Includes a set of custom attributes that can be applied to controllers/endpoints, actions and models to enrich the generated documentation. |
| [Swashbuckle.AspNetCore.Cli][swashbuckle-aspnetcore-cli] | [][swashbuckle-aspnetcore-cli] | Provides a command line interface (CLI) for retrieving OpenAPI documents directly from an application start-up assembly and then writing to a file. |
| [Swashbuckle.AspNetCore.ReDoc][swashbuckle-aspnetcore-redoc] | [][swashbuckle-aspnetcore-redoc] | Exposes an embedded version of the [Redoc UI][redoc] (an alternative to [swagger-ui][swagger-ui]). |

### Community Packages

These packages are provided by the .NET open-source community.

| **Package** | **NuGet** | **Description** |
| ----------- | --------- | --------------- |
| [Swashbuckle.AspNetCore.Filters][swashbuckle-aspnetcore-filters] | [][swashbuckle-aspnetcore-filters] | Some useful Swashbuckle.AspNetCore filters which add additional documentation, e.g. request and response examples, authorization information, etc. See its README for more details. |
| [Unchase.Swashbuckle.AspNetCore.Extensions][unchase-swashbuckle-aspnetcore-extensions] | [][unchase-swashbuckle-aspnetcore-extensions] | Some useful extensions (filters), which add additional documentation, e.g. hide `PathItems` for unaccepted roles, fix enumerations for client code generation, etc. See its README for more details. |
| [MicroElements.Swashbuckle.FluentValidation][microelements-swashbuckle-fluentvalidation] | [][microelements-swashbuckle-fluentvalidation] | Use [FluentValidation][fluentvalidation] rules instead of ComponentModel attributes to augment generated OpenAPI schemas. |
| [MMLib.SwaggerForOcelot][mmlib-swaggerforocelot] | [][mmlib-swaggerforocelot] | Aggregate documentations over microservices directly on [Ocelot API Gateway][ocelot]. |

## Configuration and Customization

The steps described above will get you up and running with minimal set up. However, Swashbuckle.AspNetCore offers a lot of flexibility to customize as you see fit.

Check out the table below for the full list of possible configuration options.

| **Component**                          | **Configuration and Customization**                                                                                                                                         |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **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)                            |
| **Swashbuckle.AspNetCore.SwaggerGen**  | [Assign Explicit OperationIds](docs/configure-and-customize-swaggergen.md#assign-explicit-operationids)                                                                     |
|                                        | [List Operations Responses](docs/configure-and-customize-swaggergen.md#list-operation-responses)                                                                            |
|                                        | [Flag Required Parameters and Schema Properties](docs/configure-and-customize-swaggergen.md#flag-required-parameters-and-schema-properties)                                 |
|                                        | [Handle Forms and File Uploads](docs/configure-and-customize-swaggergen.md#handle-forms-and-file-uploads)                                                                   |
|                                        | [Handle File Downloads](docs/configure-and-customize-swaggergen.md#handle-file-downloads)                                                                                   |
|                                        | [Include Descriptions from XML Comments](docs/configure-and-customize-swaggergen.md#include-descriptions-from-xml-comments)                                                 |
|                                        | [Provide Global API Metadata](docs/configure-and-customize-swaggergen.md#provide-global-api-metadata)                                                                       |
|                                        | [Generate Multiple OpenAPI Documents](docs/configure-and-customize-swaggergen.md#generate-multiple-openapi-documents)                                                       |
|                                        | [Omit Obsolete Operations and/or Schema Properties](docs/configure-and-customize-swaggergen.md#omit-obsolete-operations-andor-schema-properties)                            |
|                                        | [Omit Arbitrary Operations](docs/configure-and-customize-swaggergen.md#omit-arbitrary-operations)                                                                           |
|                                        | [Customize Operation Tags (e.g. for UI Grouping)](docs/configure-and-customize-swaggergen.md#customize-operation-tags-eg-for-ui-grouping)                                   |
|                                        | [Change Operation Sort Order (e.g. for UI Sorting)](docs/configure-and-customize-swaggergen.md#change-operation-sort-order-eg-for-ui-sorting)                               |
|                                        | [Customize Schema Ids](docs/configure-and-customize-swaggergen.md#customize-schema-ids)                                                                                     |
|                                        | [Override Schema for Specific Types](docs/configure-and-customize-swaggergen.md#override-schema-for-specific-types)                                                         |
|                                        | [Extend Generator with Operation, Schema & Document Filters](docs/configure-and-customize-swaggergen.md#extend-generator-with-operation-schema-and-document-filters)        |
|                                        | [Add Security Definitions and Requirements](docs/configure-and-customize-swaggergen.md#add-security-definitions-and-requirements)                                           |
|                                        | [Add Security Definitions and Requirements for Bearer auth](docs/configure-and-customize-swaggergen.md#add-security-definitions-and-requirements-for-bearer-authentication) |
|                                        | [Inheritance and Polymorphism](docs/configure-and-customize-swaggergen.md#inheritance-and-polymorphism)                                                                     |
| **Swashbuckle.AspNetCore.SwaggerUI**   | [Change Relative Path to the UI](docs/configure-and-customize-swaggerui.md#change-relative-path-to-the-ui)                                                                  |
|                                        | [Change Document Title](docs/configure-and-customize-swaggerui.md#change-document-title)                                                                                    |
|                                        | [Change CSS or JS Paths](docs/configure-and-customize-swaggerui.md#change-css-or-js-paths)                                                                                  |
|                                        | [List Multiple OpenAPI Documents](docs/configure-and-customize-swaggerui.md#list-multiple-openapi-documents)                                                                |
|                                        | [Apply swagger-ui Parameters](docs/configure-and-customize-swaggerui.md#apply-swagger-ui-parameters)                                                                        |
|                                        | [Inject Custom JavaScript](docs/configure-and-customize-swaggerui.md#inject-custom-javascript)                                                                              |
|                                        | [Inject Custom CSS](docs/configure-and-customize-swaggerui.md#inject-custom-css)                                                                                            |
|                                        | [Customize index.html](docs/configure-and-customize-swaggerui.md#customize-indexhtml)                                                                                       |
|                                        | [Enable OAuth2.0 Flows](docs/configure-and-customize-swaggerui.md#enable-oauth20-flows)                                                                                     |
|                                        | [Use client-side request and response interceptors](docs/configure-and-customize-swaggerui.md#use-client-side-request-and-response-interceptors)                            |
| **Swashbuckle.AspNetCore.Annotations** | [Install and Enable Annotations](docs/configure-and-customize-annotations.md#install-and-enable-annotations)                                                                |
|                                        | [Enrich Operation Metadata](docs/configure-and-customize-annotations.md#enrich-operation-metadata)                                                                          |
|                                        | [Enrich Response Metadata](docs/configure-and-customize-annotations.md#enrich-response-metadata)                                                                            |
|                                        | [Enrich Parameter Metadata](docs/configure-and-customize-annotations.md#enrich-parameter-metadata)                                                                          |
|                                        | [Enrich RequestBody Metadata](docs/configure-and-customize-annotations.md#enrich-requestbody-metadata)                                                                      |
|                                        | [Enrich Schema Metadata](docs/configure-and-customize-annotations.md#enrich-schema-metadata)                                                                                |
|                                        | [Apply Schema Filters to Specific Types](docs/configure-and-customize-annotations.md#apply-schema-filters-to-specific-types)                                                |
|                                        | [Add Tag Metadata](docs/configure-and-customize-annotations.md#add-tag-metadata)                                                                                            |
| **Swashbuckle.AspNetCore.Cli**         | [Retrieve OpenAPI Directly from a Startup Assembly](docs/configure-and-customize-cli.md#retrieve-openapi-directly-from-a-startup-assembly)                                  |
|                                        | [Use the CLI Tool with a Custom Host Configuration](docs/configure-and-customize-cli.md#use-the-cli-tool-with-a-custom-host-configuration)                                  |
| **Swashbuckle.AspNetCore.ReDoc**       | [Change Relative Path to the UI](docs/configure-and-customize-redoc.md#change-relative-path-to-the-ui)                                                                      |
|                                        | [Change Document Title](docs/configure-and-customize-redoc.md#change-document-title)                                                                                        |
|                                        | [Apply Redoc Parameters](docs/configure-and-customize-redoc.md#apply-redoc-parameters)                                                                                      |
|                                        | [Inject Custom CSS](docs/configure-and-customize-redoc.md#inject-custom-css)                                                                                                |
|                                        | [Customize index.html](docs/configure-and-customize-redoc.md#customize-indexhtml)                                                                                           |



[api-explorer]: https://andrewlock.net/introduction-to-the-apiexplorer-in-asp-net-core/ "Introduction to the ApiExplorer in ASP.NET Core"
[build-badge]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/actions/workflows/build.yml/badge.svg?branch=master&event=push
[build-status]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/actions?query=workflow%3Abuild+branch%3Amaster+event%3Apush "Continuous Integration for this project"
[conventional-routing]: https://learn.microsoft.com/aspnet/core/mvc/controllers/routing#conventional-routing "Routing to controller actions in ASP.NET Core - Conventional routing"
[coverage-badge]: https://codecov.io/gh/domaindrivendev/Swashbuckle.AspNetCore/branch/master/graph/badge.svg
[coverage-report]: https://codecov.io/gh/domaindrivendev/Swashbuckle.AspNetCore "Code coverage report for this project"
[fluentvalidation]: https://docs.fluentvalidation.net "FluentValidation documentation"
[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"
[ocelot]: https://github.com/ThreeMammals/Ocelot "Ocelot on GitHub"
[package-badge-downloads]: https://img.shields.io/nuget/dt/Swashbuckle.AspNetCore?logo=nuget&label=Downloads&color=blue
[package-badge-version]: https://img.shields.io/nuget/v/Swashbuckle.AspNetCore?logo=nuget&label=Latest&color=blue
[package-download]: https://www.nuget.org/packages/Swashbuckle.AspNetCore/ "Download Swashbuckle.AspNetCore from NuGet"
[redoc]: https://github.com/Redocly/redoc "The Redoc project in GitHub"
[scorecard-badge]: https://api.securityscorecards.dev/projects/github.com/domaindrivendev/Swashbuckle.AspNetCore/badge
[scorecard-report]: https://securityscorecards.dev/viewer/?uri=github.com/domaindrivendev/Swashbuckle.AspNetCore "OpenSSF Scorecard for this project"
[swashbuckle-aspnetcore-annotations]: https://www.nuget.org/packages/Swashbuckle.AspNetCore.Annotations "Swashbuckle.AspNetCore.Annotations NuGet package"
[swashbuckle-aspnetcore-cli]: https://www.nuget.org/packages/Swashbuckle.AspNetCore.Cli "Swashbuckle.AspNetCore.Cli NuGet package"
[swashbuckle-aspnetcore-filters]: https://github.com/mattfrear/Swashbuckle.AspNetCore.Filters "Swashbuckle.AspNetCore.Filters in GitHub"
[swashbuckle-aspnetcore-newtonsoft]: https://www.nuget.org/packages/Swashbuckle.AspNetCore.Newtonsoft/ "Swashbuckle.AspNetCore.Newtonsoft NuGet package"
[swashbuckle-aspnetcore-redoc]: https://www.nuget.org/packages/Swashbuckle.AspNetCore.ReDoc "Swashbuckle.AspNetCore.ReDoc NuGet package"
[swashbuckle-aspnetcore-swagger]: https://www.nuget.org/packages/Swashbuckle.AspNetCore.Swagger "Swashbuckle.AspNetCore.Swagger NuGet package"
[swashbuckle-aspnetcore-swaggergen]: https://www.nuget.org/packages/Swashbuckle.AspNetCore.SwaggerGen "Swashbuckle.AspNetCore.SwaggerGen NuGet package"
[swashbuckle-aspnetcore-swaggerui]: https://www.nuget.org/packages/Swashbuckle.AspNetCore.SwaggerUI "Swashbuckle.AspNetCore.SwaggerUI NuGet package"
[swagger]: https://swagger.io "Swagger website"
[swagger-codegen]: https://github.com/swagger-api/swagger-codegen "The Swagger Codegen project in GitHub"
[swagger-specification]: https://swagger.io/specification/ "OpenAPI Specification"
[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"

---

## File: docs/configure-and-customize-annotations.md

# Configuration and Customization of `Swashbuckle.AspNetCore.Annotations`

## Install and Enable Annotations

First install the following NuGet package into your ASP.NET Core application.

```terminal
dotnet add package Swashbuckle.AspNetCore.Annotations
```

Next in your application's startup path, enable annotations within the Swagger configuration callback:



<a id='snippet-Annotations-Enable'></a>
```cs
services.AddSwaggerGen(options =>
{
    // Other setup, then...
    options.EnableAnnotations();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L27-L33) | [anchor](#snippet-Annotations-Enable)</sup>



## Enrich Operation Metadata

Once annotations have been enabled, you can enrich the generated Operation metadata by decorating actions with `[SwaggerOperation]`.



<a id='snippet-Annotations-SwaggerOperation'></a>
```cs
[HttpPost]
[SwaggerOperation(
    Summary = "Creates a new product",
    Description = "Requires admin privileges",
    OperationId = "CreateProduct",
    Tags = ["Purchase", "Products"]
)]
public IActionResult Create([FromBody] Product product)
{
    //...
    return Ok();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L24-L37) | [anchor](#snippet-Annotations-SwaggerOperation)</sup>



## Enrich Response Metadata

ASP.NET Core provides the `ProducesResponseTypeAttribute` for listing the different responses that
can be returned by an action. These attributes can be combined with XML comments, as described
[further here](configure-and-customize-swaggergen.md#include-descriptions-from-xml-comments), to
include human-friendly descriptions with each response in the generated document. If you'd prefer
to do all of this with a single attribute, and avoid the use of XML comments, you can use one or more `[SwaggerResponse]` instead:



<a id='snippet-Annotations-SwaggerResponse'></a>
```cs
[HttpPost]
[SwaggerResponse(201, "The product was created", typeof(Product))]
[SwaggerResponse(400, "The product data is invalid")]
public IActionResult Post([FromBody] Product product)
{
    //...
    return Created();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L39-L48) | [anchor](#snippet-Annotations-SwaggerResponse)</sup>



## Enrich Parameter Metadata

You can annotate path, query or header-bound parameters or properties (i.e. decorated with `[FromRoute]`, `[FromQuery]`
or `[FromHeader]`) with a `SwaggerParameterAttribute` to enrich the corresponding `Parameter` metadata that's generated by Swashbuckle.AspNetCore:



<a id='snippet-Annotations-SwaggerParameter'></a>
```cs
[HttpGet]
public IActionResult GetProducts(
    [FromQuery, SwaggerParameter("Search keywords", Required = true)] string keywords)
{
    //...
    return Ok();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L50-L58) | [anchor](#snippet-Annotations-SwaggerParameter)</sup>



## Enrich RequestBody Metadata

You can annotate body-bound parameters or properties (i.e. decorated with `[FromBody]`) with `[SwaggerRequestBody]` to enrich
the corresponding `RequestBody` metadata that's generated by Swashbuckle.AspNetCore:



<a id='snippet-Annotations-SwaggerRequestBody'></a>
```cs
[HttpPost]
public IActionResult SubmitProduct(
    [FromBody, SwaggerRequestBody("The product payload", Required = true)] Product product)
{
    //...
    return Created();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L60-L68) | [anchor](#snippet-Annotations-SwaggerRequestBody)</sup>



## Enrich Schema Metadata

You can annotate classes or properties with `[SwaggerSchema]` to enrich the corresponding `Schema` metadata that's generated by Swashbuckle.AspNetCore:



<a id='snippet-Annotations-SwaggerSchema'></a>
```cs
[SwaggerSchema(Required = ["Description"])]
public class Product
{
    [SwaggerSchema("The product identifier", ReadOnly = true)]
    public int Id { get; set; }

    [SwaggerSchema("The product description")]
    public string Description { get; set; } = string.Empty;

    [SwaggerSchema("The date it was created", Format = "date")]
    public DateTime DateCreated { get; set; }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/Product.cs#L5-L18) | [anchor](#snippet-Annotations-SwaggerSchema)</sup>



> [!NOTE]
> In OpenAPI, serialized objects **and** contained properties are represented as `Schema` instances, hence why this annotation can
> be applied to both classes and properties. Also, `required` properties are specified as an array of property names on the top-level schema
> as opposed to a flag on each individual property.

## Apply Schema Filters to Specific Types

The `Swashbuckle.AspNetCore.SwaggerGen` NuGet package provides several extension points, including
[Schema Filters](configure-and-customize-swaggergen.md#extend-generator-with-operation-schema--document-filter) for
customizing **all** generated Schemas. However, there may be cases where it's preferable to apply a filter to a specific
Schema. For example, if you'd like to include an example for a specific type in your API. This can be done by decorating the
type with `[SwaggerSchemaFilter]`:

📝 `Item.cs`



<a id='snippet-Annotations-SchemaModel'></a>
```cs
[SwaggerSchemaFilter(typeof(ItemSchemaFilter))]
public class Item
{
    //...
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/Item.cs#L5-L11) | [anchor](#snippet-Annotations-SchemaModel)</sup>



📝 `ItemSchemaFilter.cs`



<a id='snippet-Annotations-SchemaFilter'></a>
```cs
public class ItemSchemaFilter : ISchemaFilter
{
    public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
    {
        if (schema is OpenApiSchema concrete)
        {
            concrete.Example = new JsonObject
            {
                ["Id"] = 1,
                ["Description"] = "An awesome item"
            };
        }
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ItemSchemaFilter.cs#L7-L22) | [anchor](#snippet-Annotations-SchemaFilter)</sup>



## Add Tag Metadata

By default, the OpenAPI generator will tag all operations with the controller name for MVC applications. This tag is then
used to drive the operation groupings in [swagger-ui](https://github.com/swagger-api/swagger-ui). If you'd like to provide
a description for each of these groups, you can do so by adding metadata for each controller name tag using `[SwaggerTag]`:



<a id='snippet-Annotations-SwaggerTag'></a>
```cs
[SwaggerTag("Create, read, update and delete Items")]
public class ItemsController
{
    //...
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ItemsController.cs#L5-L11) | [anchor](#snippet-Annotations-SwaggerTag)</sup>



> [!NOTE]
> This will add the above description specifically to the tag named `Items`. Therefore, you should avoid using this attribute
> if you're tagging Operations with something other than the controller name - e.g. if you're customizing the tagging behavior with `TagActionsBy`.

## List Known Subtypes for Inheritance and Polymorphism

If you want to use Swashbuckle's [inheritance and/or polymorphism behavior](configure-and-customize-swaggergen.md#inheritance-and-polymorphism),
you can use annotations to _explicitly_ indicate the "known" subtypes for a given base type. This will override the default selector function,
which selects _all_ subtypes in the same assembly as the base type, and therefore needs to be explicitly enabled when you enable Annotations:

📝 `Startup.cs`



<a id='snippet-Annotations-EnablePolymorphism'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L35-L40) | [anchor](#snippet-Annotations-EnablePolymorphism)</sup>



📝 `Shape.cs`



<a id='snippet-Annotations-Shape'></a>
```cs
[JsonDerivedType(typeof(Rectangle))]
[JsonDerivedType(typeof(Circle))]
public abstract class Shape
{
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/Shape.cs#L5-L11) | [anchor](#snippet-Annotations-Shape)</sup>



## Enrich Polymorphic Base Classes with Discriminator Metadata

If you're using annotations to _explicitly_ indicate the "known" subtypes for a polymorphic base type, you can combine
`[JsonPolymorphic]` with `[JsonDerivedType]` to provide additional metadata about the "discriminator" property, which will
then be incorporated into the generated schema definition:

📝 `Startup.cs`



<a id='snippet-Annotations-EnablePolymorphism'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L35-L40) | [anchor](#snippet-Annotations-EnablePolymorphism)</sup>



📝 `ShapeWithDiscriminator.cs`



<a id='snippet-Annotations-ShapeWithDiscriminator'></a>
```cs
[JsonPolymorphic(TypeDiscriminatorPropertyName = "shapeType")]
[JsonDerivedType(typeof(Rectangle), "rectangle")]
[JsonDerivedType(typeof(Circle), "circle")]
public abstract class ShapeWithDiscriminator
{
    // Avoid using a JsonPolymorphicAttribute.TypeDiscriminatorPropertyName
    // that conflicts with a property in your type hierarchy.
    // Related issue: https://github.com/dotnet/runtime/issues/72170
}

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ShapeType
{
    Circle,
    Rectangle
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ShapeWithDiscriminator.cs#L5-L22) | [anchor](#snippet-Annotations-ShapeWithDiscriminator)</sup>



This indicates that the corresponding payload will have a `"shapeType"` property to discriminate between subtypes, and that property
will have a value of `"rectangle"` if the payload represents a `Rectangle` type and a value of `"circle"` if it represents a `Circle` type.
This detail will be described in the generated schema definition as follows:

```yaml
schema: {
  oneOf: [
    {
      $ref: "#/components/schemas/Rectangle"
    },
    {
      $ref: "#/components/schemas/Circle"
    },
  ],
  discriminator: {
    propertyName: shapeType,
    mapping: {
      rectangle: "#/components/schemas/Rectangle",
      circle: "#/components/schemas/Circle",
    }
  }
}
```

---

## File: docs/configure-and-customize-cli.md

# Configuration and Customization of `Swashbuckle.AspNetCore.Cli`

## Retrieve OpenAPI Directly from a Startup Assembly

Once your application has been set up with Swashbuckle.AspNetCore (see [Getting Started](../README.md#getting-started)), you can
use the Swashbuckle.OpenAPI CLI tool to retrieve OpenAPI JSON documents directly from your application's startup assembly, and write
it to a file. This can be useful if you want to incorporate OpenAPI generation into a CI/CD process, or if you want to serve
it from static file at run-time.

It's packaged as a [.NET Tool](https://learn.microsoft.com/dotnet/core/tools/global-tools) that can be installed and used via the .NET SDK.

> [!WARNING]
> The tool needs to load your Startup DLL and its dependencies at runtime. Therefore, you should use a version of the `dotnet` CLI
> that is compatible with your application. For example, if your app targets `net10.0`, then you should use version 10.0.xxx of the
> .NET SDK to run the CLI tool.

### Using the tool with the .NET SDK

#### Install as a Global Tool

To install as a [global tool](https://learn.microsoft.com/dotnet/core/tools/global-tools#install-a-global-tool):

```terminal
dotnet tool install -g Swashbuckle.AspNetCore.Cli
```

#### Install as a local tool

1. In your solution root directory, create a tool manifest file:

    ```terminal
    dotnet new tool-manifest
    ```

2. Install as a [local tool](https://learn.microsoft.com/dotnet/core/tools/global-tools#install-a-local-tool)

    ```terminal
    dotnet tool install Swashbuckle.AspNetCore.Cli
    ```

### Usage

1. Verify that the tool was installed correctly

    ```termainal
    swagger tofile --help
    ```

2. Generate an OpenAPI document from your application's startup assembly

    ```terminal
    swagger tofile --output [output] [startupassembly] [swaggerdoc]
    ```

    Placeholders and their meaning:
    * `[output]`: the relative path where the OpenAPI JSON document will be output to;
    * `[startupassembly]`: the relative path to your application's startup assembly;
    * `[swaggerdoc]`: the name of the OpenAPI document you want to generate, as configured in your application.

## Use the CLI Tool with a Custom Host Configuration

By default, the tool will execute in the context of a "default" web host. However, in some cases you may want to
bring your own host environment, for example if you've configured a custom DI container such as Autofac. For this
scenario, the Swashbuckle CLI tool exposes a convention-based hook for your application.

That is, if your application contains a class that meets either of the following naming conventions, then that class
will be used to provide a host for the CLI tool to run in.

* `public class SwaggerHostFactory`, containing a public static method called `CreateHost` with return type `IHost`
* `public class SwaggerWebHostFactory`, containing a public static method called `CreateWebHost` with return type `IWebHost`

For example, the following class could be used to leverage the same host configuration as your application:



<a id='snippet-SwaggerHostFactory'></a>
```cs
public class SwaggerHostFactory
{
    public static IHost CreateHost()
        => MyApplication.CreateHostBuilder([]).Build();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/SwaggerHostFactory.cs#L3-L9) | [anchor](#snippet-SwaggerHostFactory)</sup>

---

## File: docs/configure-and-customize-redoc.md

# Configuration and Customization of `Swashbuckle.AspNetCore.ReDoc`

## Change Relative Path to the UI

By default, the Redoc UI will be exposed at `/api-docs`. If necessary, you can alter this when enabling the Redoc middleware:



<a id='snippet-Redoc-RoutePrefix'></a>
```cs
app.UseReDoc(options =>
{
    options.RoutePrefix = "docs";
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L142-L147) | [anchor](#snippet-Redoc-RoutePrefix)</sup>



## Change Document Title

By default, the Redoc UI will have a generic document title. You can alter this when enabling the Redoc middleware:



<a id='snippet-Redoc-DocumentTitle'></a>
```cs
app.UseReDoc(options =>
{
    options.DocumentTitle = "My API Docs";
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L149-L154) | [anchor](#snippet-Redoc-DocumentTitle)</sup>



## Apply Redoc Parameters

Redoc ships with its own set of configuration parameters, all described [in the Redoc documentation][redoc-options].
In Swashbuckle.AspNetCore, most of these are surfaced through the Redoc middleware options:



<a id='snippet-Redoc-CustomOptions'></a>
```cs
app.UseReDoc(options =>
{
    options.SpecUrl("/v1/swagger.json");
    options.EnableUntrustedSpec();
    options.ScrollYOffset(10);
    options.HideHostname();
    options.HideDownloadButton();
    options.ExpandResponses("200,201");
    options.RequiredPropsFirst();
    options.NoAutoAuth();
    options.PathInMiddlePanel();
    options.HideLoading();
    options.NativeScrollbars();
    options.DisableSearch();
    options.OnlyRequiredInSamples();
    options.SortPropsAlphabetically();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L156-L174) | [anchor](#snippet-Redoc-CustomOptions)</sup>



> [!NOTE]
> Using `options.SpecUrl("/v1/swagger.json")` multiple times within the same `UseReDoc(...)` will not add multiple URLs.

## Inject Custom CSS

To tweak the look and feel, you can inject additional CSS stylesheets by adding them to your `wwwroot` folder and specifying
the relative paths in the middleware options:



<a id='snippet-Redoc-CustomCSS'></a>
```cs
app.UseReDoc(options =>
{
    options.InjectStylesheet("/redoc/custom.css");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L176-L181) | [anchor](#snippet-Redoc-CustomCSS)</sup>



It is also possible to modify the theme by using the `AdditionalItems` property. More information can be found
[in the Redoc documentation][redoc-options].



<a id='snippet-Redoc-ModifyTheme'></a>
```cs
app.UseReDoc(options =>
{
    options.ConfigObject.AdditionalItems = new Dictionary<string, object>
    {
        // Configured additional options
    };
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L183-L191) | [anchor](#snippet-Redoc-ModifyTheme)</sup>



## Customize index.html

To customize the UI beyond the basic options listed above, you can provide your own version of the Redoc `index.html` page:



<a id='snippet-Redoc-CustomIndexHtml'></a>
```cs
app.UseReDoc(options =>
{
    options.IndexStream = () => typeof(Program).Assembly
        .GetManifestResourceStream("CustomIndex.ReDoc.index.html"); // Requires file to be added as an embedded resource
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L193-L199) | [anchor](#snippet-Redoc-CustomIndexHtml)</sup>



```xml

  
    
  

```

> [!TIP]
> To get started, you should base your custom `index.html` on the [default version](../src/Swashbuckle.AspNetCore.ReDoc/index.html).

## Use `MapReDoc` with endpoint routing

`MapReDoc` is an endpoint-routing alternative to `UseReDoc`. The options API is the same, so all customization examples on this page also apply when using `MapReDoc`.



<a id='snippet-Redoc-MapReDoc'></a>
```cs
app.MapReDoc();
```
<sup>[snippet source](/test/WebSites/WebApi.Map/Program.cs#L33-L35) | [anchor](#snippet-Redoc-MapReDoc)</sup>



The main differences are:

- **Use**ReDoc adds middleware directly to the request pipeline and returns `IApplicationBuilder`.
- **Map**ReDoc maps ReDoc via endpoint routing and returns `IEndpointConventionBuilder`.

- Because `MapReDoc` returns an endpoint convention builder, you can attach endpoint metadata/conventions (for example, authorization policies) directly to the mapped ReDoc endpoint.



<a id='snippet-Redoc-MapReDoc-RequireAuthorization'></a>
```cs
app.MapReDoc("redoc-auth")
   .RequireAuthorization(); // Remember to also add RequireAuthorization to MapSwagger
```
<sup>[snippet source](/test/WebSites/WebApi.Map/Program.cs#L37-L40) | [anchor](#snippet-Redoc-MapReDoc-RequireAuthorization)</sup>



[redoc-options]: https://github.com/Redocly/redoc/blob/main/docs/deployment/html.md#the-redoc-object

---

## File: docs/configure-and-customize-swagger.md

# Configuration and Customization of `Swashbuckle.AspNetCore.Swagger`

## Change the Path for OpenAPI JSON Endpoints

By default, OpenAPI (Swagger) JSON will be exposed at the following route - `/swagger/{documentName}/swagger.json`.
If necessary, you can change this when enabling the Swagger middleware.

> [!IMPORTANT]
> Custom routes **must** include the `{documentName}` parameter.



<a id='snippet-Swagger-RouteTemplate'></a>
```cs
app.UseSwagger(options =>
{
    options.RouteTemplate = "api-docs/{documentName}/swagger.json";
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L201-L206) | [anchor](#snippet-Swagger-RouteTemplate)</sup>



> [!NOTE]
> If you're using the SwaggerUI middleware, you'll also need to update its configuration to reflect the new endpoints:
>
> ```csharp
> app.UseSwaggerUI(options =>
> {
>     options.SwaggerEndpoint("/api-docs/v1/swagger.json", "My API V1");
> });
> ```
>
> If you also need to update the relative path that the UI itself is available on, you'll need to follow the instructions
> found in [Change Relative Path to the UI](configure-and-customize-swaggerui.md#change-relative-path-to-the-ui).

## Modify OpenAPI with Request Context

If you need to set some OpenAPI metadata based on the current request, you can configure a filter that's executed prior to serializing the document.



<a id='snippet-Swagger-ModifyWithHttpRequest'></a>
```cs
app.UseSwagger(options =>
{
    options.PreSerializeFilters.Add((document, request) =>
    {
        document.Servers = [new OpenApiServer { Url = $"{request.Scheme}://{request.Host.Value}" }];
    });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L208-L216) | [anchor](#snippet-Swagger-ModifyWithHttpRequest)</sup>



The `OpenApiDocument` and the current `HttpRequest` are both passed to the filter, which provides a lot of flexibility.
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:



<a id='snippet-Swagger-OpenAPI3.1'></a>
```cs
app.UseSwagger(options =>
{
    options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L218-L223) | [anchor](#snippet-Swagger-OpenAPI3.1)</sup>



## 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
OpenAPI Specification. However, to support backwards compatibility, you can opt to continue exposing it in the Swagger 2.0
format with the following option:



<a id='snippet-Swagger-Swagger2.0'></a>
```cs
app.UseSwagger(options =>
{
    options.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0;
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L225-L230) | [anchor](#snippet-Swagger-Swagger2.0)</sup>



## Working with Virtual Directories and Reverse Proxies

Virtual directories and reverse proxies can cause issues for applications that generate links and redirects, particularly
if the app returns *absolute* URLs based on the `Host` header and other information from the current request. To avoid these
issues, Swashbuckle.AspNetCore uses *relative* URLs where possible, and encourages their use when configuring the SwaggerUI
and ReDoc middleware.

For example, to wire up the SwaggerUI middleware, you provide the URL to one or more OpenAPI documents. This is the URL
that [swagger-ui](https://github.com/swagger-api/swagger-ui), a client-side application, will call to retrieve your API metadata. To ensure this works behind
virtual directories and reverse proxies, you should express this relative to the `RoutePrefix` of swagger-ui itself:



<a id='snippet-Swagger-ReverseProxy'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.RoutePrefix = "swagger";
    options.SwaggerEndpoint("v1/swagger.json", "My API V1");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L232-L238) | [anchor](#snippet-Swagger-ReverseProxy)</sup>



## Customizing how the OpenAPI document is serialized

By default, Swashbuckle.AspNetCore will serialize the OpenAPI document using the `Serialize*` methods on the OpenAPI document object. If a
customized serialization is desired,  it is possible to create a custom document serializer that implements the `ISwaggerDocumentSerializer` interface.
This can be set on the `SwaggerOptions` in the service collection using `ConfigureSwagger()`:



<a id='snippet-Swagger-CustomSerializerServices'></a>
```cs
services.ConfigureSwagger(options =>
{
    options.SetCustomDocumentSerializer<CustomDocumentSerializer>();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L42-L47) | [anchor](#snippet-Swagger-CustomSerializerServices)</sup>



> [!NOTE]
> If you plan on using the command line tool to generate OpenAPI specification files, this must be done on the service
> collection using `ConfigureSwagger()`.

When the command line tool is not used, it can also be done on the application host:



<a id='snippet-Swagger-CustomSerializerMiddleware'></a>
```cs
app.UseSwagger(options =>
{
    options.SetCustomDocumentSerializer<CustomDocumentSerializer>();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L240-L245) | [anchor](#snippet-Swagger-CustomSerializerMiddleware)</sup>

---

## File: docs/configure-and-customize-swaggergen.md

# Configuration and Customization of `Swashbuckle.AspNetCore.SwaggerGen`

## Assign Explicit OperationIds

In OpenAPI, operations may be assigned an `operationId`. This ID must be unique among all operations described in the API.
Tools and libraries (e.g. client generators) may use the `operationId` to uniquely identify an operation, therefore, it is
recommended to follow common programming naming conventions.

Auto-generating an ID that matches these requirements, while also providing a name that would be meaningful in client libraries,
is a non-trivial task and thus Swashbuckle.AspNetCore omits the `operationId` by default. However, if necessary, you can assign
`operationIds` by decorating individual routes or by providing a custom strategy.

### Option 1: Decorate routes with a `Name` property



<a id='snippet-SwaggerGen-NamedRoute'></a>
```cs
// operationId = "GetProductById"
[HttpGet("{id}", Name = "GetProductById")]
public IActionResult Get(int id)
{
    // ...
    return Ok();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L70-L78) | [anchor](#snippet-SwaggerGen-NamedRoute)</sup>



### Option 2: Provide a custom strategy

📝 `Startup.cs`



<a id='snippet-SwaggerGen-CustomNamingStrategyConfiguration'></a>
```cs
services.AddSwaggerGen(options =>
{
    // Other configuration...

    // Use method name as operationId
    options.CustomOperationIds(apiDescription =>
    {
        return apiDescription.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null;
    });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L49-L60) | [anchor](#snippet-SwaggerGen-CustomNamingStrategyConfiguration)</sup>



📝 `ProductsController.cs`



<a id='snippet-SwaggerGen-CustomNamingStrategyEndpoint'></a>
```cs
// operationId = "GetProductById"
[HttpGet("/product/{id}")]
public IActionResult GetProductById(int id)
{
    // ...
    return Ok();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L80-L88) | [anchor](#snippet-SwaggerGen-CustomNamingStrategyEndpoint)</sup>



> [!NOTE]
> With either approach, API authors are responsible for ensuring the uniqueness of `operationIds` across all operations.

## List Operation Responses

By default, Swashbuckle.AspNetCore will generate an HTTP `"200"` response for each operation. If the endpoint returns a
response object, then this will be used to generate a schema for the response body. For example:



<a id='snippet-SwaggerGen-ImplicitResponse'></a>
```cs
[HttpPost("{id}")]
public Product GetById(int id)
{
    // ...
    return new Product();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L90-L97) | [anchor](#snippet-SwaggerGen-ImplicitResponse)</sup>



This endpoint will produce the following response metadata:

```yaml
responses: {
  200: {
    content: {
      "application/json": {
        schema: {
          $ref: "#/components/schemas/Product"
        }
      }
    }
  }
}
```

### Explicit Responses

If you need to specify a different status code and/or additional responses, or your MVC actions return `IActionResult` instead
of a response object, you can explicitly describe responses with `[ProducesResponseType]` which is part of ASP.NET Core. For example:



<a id='snippet-SwaggerGen-ExplicitReponses'></a>
```cs
[HttpPost("product/{id}")]
[ProducesResponseType(typeof(Product), 200)]
[ProducesResponseType(typeof(IDictionary<string, string>), 400)]
[ProducesResponseType(500)]
public IActionResult GetProductInfoById(int id)
{
    // ...
    return Ok();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L99-L109) | [anchor](#snippet-SwaggerGen-ExplicitReponses)</sup>



This endpoint will produce the following response metadata:

```yaml
responses: {
  200: {
    content: {
      "application/json": {
        schema: {
          $ref: "#/components/schemas/Product"
        }
      }
    }
  },
  400: {
    content: {
      "application/json": {
        schema: {
          type: "object",
          additionalProperties: {
            type: "string"
          }
        }
      }
    }
  },
  500: {
    content: {}
  }
}
```

## Flag Required Parameters and Schema Properties

In an OpenAPI document, you can flag parameters and schema properties that are required for a request. If a parameter
(top-level or property-based) is decorated with `[BindRequired]` or `[Required]`, then Swashbuckle.AspNetCore will automatically
flag it as a `required` parameter in the generated OpenAPI document:

📝 `ProductsController.cs`



<a id='snippet-SwaggerGen-RequiredParametersEndpoint'></a>
```cs
public IActionResult Search([FromQuery, BindRequired] string keywords, [FromQuery] PagingOptions paging)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // ...
    return Ok();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L111-L122) | [anchor](#snippet-SwaggerGen-RequiredParametersEndpoint)</sup>



📝 `PagingOptions.cs`



<a id='snippet-SwaggerGen-RequiredParametersModel'></a>
```cs
public class PagingOptions
{
    [Required]
    public int PageNumber { get; set; }

    public int PageSize { get; set; }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/PagingOptions.cs#L5-L13) | [anchor](#snippet-SwaggerGen-RequiredParametersModel)</sup>



In addition to parameters, Swashbuckle.AspNetCore will also honor `[Required]` when used in a model that's bound to the request body.
In this case, the decorated properties will be flagged as `required` properties in the body description:

📝 `ProductsController.cs`



<a id='snippet-SwaggerGen-RequiredParametersFromBody'></a>
```cs
public IActionResult CreateNewProduct([FromBody] NewProduct product)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // ...
    return Created();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L124-L135) | [anchor](#snippet-SwaggerGen-RequiredParametersFromBody)</sup>



📝 `NewProduct.cs`



<a id='snippet-SwaggerGen-NewProduct'></a>
```cs
public class NewProduct
{
    [Required]
    public string Name { get; set; } = string.Empty;

    public string Description { get; set; } = string.Empty;
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/NewProduct.cs#L5-L13) | [anchor](#snippet-SwaggerGen-NewProduct)</sup>



## Handle Forms and File Uploads

This MVC controller will accept two form field values and one named file upload from the same form:



<a id='snippet-SwaggerGen-UploadFile'></a>
```cs
[HttpPost]
public void UploadFile([FromForm] string description, [FromForm] DateTime clientDate, IFormFile file)
{
    // ...
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L137-L143) | [anchor](#snippet-SwaggerGen-UploadFile)</sup>



> [!IMPORTANT]
> As per the [ASP.NET Core documentation](https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads), you're not supposed to
> decorate `IFormFile` parameters with the `[FromForm]` attribute as the binding source is automatically inferred from the type. In fact,
> the inferred value is `BindingSource.FormFile` and if you apply the attribute it will be set to `BindingSource.Form` instead, which breaks
> `ApiExplorer`, the metadata component that ships with ASP.NET Core and is heavily relied on by Swashbuckle.AspNetCore. One particular issue here is
> that SwaggerUI will not treat the parameter as a file and so will not display a file upload button, if you do mistakenly include this attribute.

## Handle File Downloads

> [!IMPORTANT]
> `ApiExplorer` (the ASP.NET Core metadata component that Swashbuckle.AspNetCore is built on) **does not** surface the `FileResult` types by
> default and so you need to explicitly configure it to do so with `[ProducesResponseType]`:



<a id='snippet-SwaggerGen-DownloadFile'></a>
```cs
[HttpGet("download/{fileName}")]
[ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK, "image/jpeg")]
public FileStreamResult GetImage(string fileName)
{
    // ...
    return new FileStreamResult(Stream.Null, "image/jpeg");
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L145-L153) | [anchor](#snippet-SwaggerGen-DownloadFile)</sup>



## Include Descriptions from XML Comments

To enhance the generated docs with human-friendly descriptions, you can annotate endpoints and models with
[XML Comments](https://learn.microsoft.com/dotnet/csharp/language-reference/xmldoc/) and configure Swashbuckle.AspNetCore
to include those comments into the generated OpenAPI document.

First open the Properties dialog for your project, click the "Build" tab and ensure that "XML documentation file" is checked, or add an
`<GenerateDocumentationFile>true</GenerateDocumentationFile>` element to a `` in your `.csproj` file. This
will produce a file containing all XML comments at build-time.

> At this point, any classes or methods that are **not** annotated with XML comments will trigger a build warning. To suppress this,
> enter the warning code `1591` into the _"Suppress warnings"_ field in the Properties dialog or add `<NoWarn>$(NoWarn);1591</NoWarn>` to a
> `` of your `.csproj` project file.

Next configure Swashbuckle.AspNetCore to incorporate the XML comments on file into the generated OpenAPI JSON:



<a id='snippet-SwaggerGen-ConfigureXmlDocumentation'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.SwaggerDoc(
        "v1",
        new OpenApiInfo
        {
            Title = "My API - V1",
            Version = "v1"
        }
    );

    options.IncludeXmlComments(Assembly.GetExecutingAssembly());
    // or options.IncludeXmlComments(typeof(MyController).Assembly));
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L62-L77) | [anchor](#snippet-SwaggerGen-ConfigureXmlDocumentation)</sup>



Next annotate your endpoints with `summary`, `remarks`, `param` and/or `response` tags as desired:



<a id='snippet-SwaggerGen-EndpointWithXmlComments'></a>
```cs
/// 
/// Retrieves a specific product line by unique id
/// 
/// <remarks>Awesomeness!</remarks>
/// The product line id
/// <response code="200">Product line retrieved</response>
/// <response code="404">Product line not found</response>
/// <response code="500">Oops! Can't lookup your product line right now</response>
[HttpGet("product/{id}")]
[ProducesResponseType(typeof(ProductLine), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public ProductLine GetProductBySystemId(int id)
{
    // ...
    return new ProductLine();
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L155-L173) | [anchor](#snippet-SwaggerGen-EndpointWithXmlComments)</sup>



Then annotate your types with `summary` and `example` tags, other tags (`remarks`, `para`, etc.) are not supported:



<a id='snippet-SwaggerGen-ClassWithXmlComments'></a>
```cs
public class ProductLine
{
    /// 
    /// The name of the product
    /// 
    /// <example>Men's basketball shoes</example>
    public string Name { get; set; } = string.Empty;

    /// 
    /// Quantity left in stock
    /// 
    /// <example>10</example>
    public int AvailableStock { get; set; }

    /// 
    /// The sizes the product is available in
    /// 
    /// <example>["Small", "Medium", "Large"]</example>
    public List<string> Sizes { get; set; } = [];
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductLine.cs#L3-L24) | [anchor](#snippet-SwaggerGen-ClassWithXmlComments)</sup>



Finally, rebuild your project to update the XML Comments file and navigate to the OpenAPI JSON endpoint. Note how the descriptions are
mapped onto corresponding OpenAPI properties.

> [!NOTE]
> You can also provide OpenAPI schema descriptions by annotating your API models and their properties with `` tags. If you
> have multiple XML comments files (e.g. separate libraries for controllers and models), you can invoke the `IncludeXmlComments` method
> multiple times and they will all be merged into the generated OpenAPI document.

## Provide Global API Metadata

In addition to `"PathItems"`, `"Operations"` and `"Responses"`, which Swashbuckle.AspNetCore generates for you, OpenAPI also supports
[global metadata](https://swagger.io/specification/#openapi-object). For example, you can provide a full description for your API, terms
of service or even contact and licensing information:



<a id='snippet-SwaggerGen-GlobalMetadata'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1",
        new OpenApiInfo
        {
            Title = "My API - V1",
            Version = "v1",
            Description = "A sample API to demo Swashbuckle",
            TermsOfService = new Uri("http://tempuri.org/terms"),
            Contact = new OpenApiContact
            {
                Name = "Joe Developer",
                Email = "joe.developer@tempuri.org"
            },
            License = new OpenApiLicense
            {
                Name = "Apache 2.0",
                Url = new Uri("https://www.apache.org/licenses/LICENSE-2.0.html")
            }
        }
    );
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L79-L102) | [anchor](#snippet-SwaggerGen-GlobalMetadata)</sup>



> [!TIP]
> Use IntelliSense to see what other members are available.

## Generate Multiple OpenAPI Documents

With the setup described above, the generator will include all API operations in a single Swagger document. However, you can
create multiple documents if necessary. For example, you may want a separate document for each version of your API. To do this, start
by defining multiple Swagger documents in your application startup code:



<a id='snippet-SwaggerGen-MultipleDocuments'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API - V1", Version = "v1" });
    options.SwaggerDoc("v2", new OpenApiInfo { Title = "My API - V2", Version = "v2" });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L104-L110) | [anchor](#snippet-SwaggerGen-MultipleDocuments)</sup>



> [!NOTE]
> Take note of the first argument to SwaggerDoc. It **must** be a URI-friendly name that uniquely identifies the document.
> It's subsequently used to make up the path for requesting the corresponding Swagger JSON. For example, with the default
> routing, the above documents will be available at `/swagger/v1/swagger.json` and `/swagger/v2/swagger.json`.

Next, you'll need to inform Swashbuckle which actions to include in each document. Although this can be customized (see below), by
default, the generator will use the `ApiDescription.GroupName` property, part of the built-in metadata layer that ships with
ASP.NET Core, to make this distinction. You can set this by decorating individual actions or by applying an application-wide convention.

### Decorate Individual Actions

To include an action in a specific Swagger document, decorate it with `[ApiExplorerSettings]` and set `GroupName` to the corresponding
document name (case sensitive):



<a id='snippet-SwaggerGen-EndpointGroupName'></a>
```cs
[HttpPost]
[ApiExplorerSettings(GroupName = "v2")]
public void PostLine([FromBody] ProductLine product)
{
    // ...
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L175-L182) | [anchor](#snippet-SwaggerGen-EndpointGroupName)</sup>



### Assign Actions to Documents by Convention

To group by convention instead of decorating every action, you can apply a custom controller or action convention. For example, you
could wire up the following convention to assign actions to documents based on the controller namespace.

📝 `ApiExplorerGroupPerVersionConvention.cs`



<a id='snippet-SwaggerGen-ControllerModelConvention'></a>
```cs
public class ApiExplorerGroupPerVersionConvention : IControllerModelConvention
{
    public void Apply(ControllerModel controller)
    {
        var controllerNamespace = controller.ControllerType.Namespace; // e.g. "Controllers.V1"
        var apiVersion = controllerNamespace?.Split('.').Last().ToLower();

        controller.ApiExplorer.GroupName = apiVersion;
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ApiExplorerGroupPerVersionConvention.cs#L5-L16) | [anchor](#snippet-SwaggerGen-ControllerModelConvention)</sup>



📝 `Startup.cs`



<a id='snippet-SwaggerGen-ConfigureControllerModelConvention'></a>
```cs
services.AddMvc(options =>
    options.Conventions.Add(new ApiExplorerGroupPerVersionConvention())
);
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L112-L116) | [anchor](#snippet-SwaggerGen-ConfigureControllerModelConvention)</sup>



### Customize the Action Selection Process

When selecting actions for a given Swagger document, the generator invokes a `DocInclusionPredicate` against every `ApiDescription`
that's surfaced by the framework. The default implementation inspects `ApiDescription.GroupName` and returns `true` if the value is either null
or equal to the requested document name. However, you can also provide a custom inclusion predicate. For example, if you're using an
attribute-based approach to implement API versioning (e.g. `Microsoft.AspNetCore.Mvc.Versioning`), you could configure a custom predicate that leverages the versioning attributes instead:



<a id='snippet-SwaggerGen-DocInclusionPredicate'></a>
```cs
options.DocInclusionPredicate((docName, apiDesc) =>
{
    if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo))
    {
        return false;
    }

    var versions = methodInfo.DeclaringType?
        .GetCustomAttributes(true)
        .OfType<ApiVersionAttribute>()
        .SelectMany(attribute => attribute.Versions) ?? [];

    return versions.Any(version => $"v{version}" == docName);
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/SwaggerGenOptionsExtensions.cs#L10-L25) | [anchor](#snippet-SwaggerGen-DocInclusionPredicate)</sup>



### Exposing Multiple Documents through the UI

If you're using the `SwaggerUI` middleware, you'll need to specify any additional OpenAPI endpoints you want to expose.
See [List Multiple OpenAPI Documents](configure-and-customize-swaggerui.md#list-multiple-openapi-documents) for more information.

## Omit Obsolete Operations and/or Schema Properties

The [OpenAPI specification][swagger-specification] includes a `deprecated` flag for indicating that an operation is deprecated
(obsolete) and should be refrained from being used. The OpenAPI generator will automatically set this flag if the corresponding action is
decorated with the `[Obsolete]` attribute. However, instead of setting a flag, you can configure the generator to ignore obsolete actions altogether:



<a id='snippet-SwaggerGen-IgnoreObsoleteActions'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.IgnoreObsoleteActions();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L118-L123) | [anchor](#snippet-SwaggerGen-IgnoreObsoleteActions)</sup>



A similar approach can also be used to omit obsolete properties from `Schemas` in the OpenAPI document. That is, you can decorate
model properties with `[Obsolete]` and configure Swashbuckle.AspNetCore to omit those properties when generating JSON schemas:



<a id='snippet-SwaggerGen-IgnoreObsoleteProperties'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.IgnoreObsoleteProperties();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L125-L130) | [anchor](#snippet-SwaggerGen-IgnoreObsoleteProperties)</sup>



## Omit Arbitrary Operations

You can omit operations from the OpenAPI output by decorating individual actions or by applying an application-wide convention.

### Decorate Individual Actions

To omit a specific action, decorate it with `[ApiExplorerSettings]` and set the `IgnoreApi` property to `true`:



<a id='snippet-SwaggerGen-HiddenByAttribute'></a>
```cs
[HttpDelete("{id}")]
[ApiExplorerSettings(IgnoreApi = true)]
public void Delete(int id)
{
    // ...
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ProductsController.cs#L184-L191) | [anchor](#snippet-SwaggerGen-HiddenByAttribute)</sup>



### Omit Actions by Convention

To omit actions by convention instead of decorating them individually, you can apply a custom action convention. For example, you
could wire up the following convention to only document `GET` operations:

📝 `ApiExplorerGetsOnlyConvention.cs`



<a id='snippet-SwaggerGen-IActionModelConvention'></a>
```cs
public class ApiExplorerGetsOnlyConvention : IActionModelConvention
{
    public void Apply(ActionModel action)
    {
        action.ApiExplorer.IsVisible = action.Attributes.OfType<HttpGetAttribute>().Any();
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/ApiExplorerGetsOnlyConvention.cs#L6-L14) | [anchor](#snippet-SwaggerGen-IActionModelConvention)</sup>



📝 `Startup.cs`



<a id='snippet-SwaggerGen-HiddenByConventionConfiguration'></a>
```cs
services.AddMvc(options =>
    options.Conventions.Add(new ApiExplorerGetsOnlyConvention())
);
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L132-L136) | [anchor](#snippet-SwaggerGen-HiddenByConventionConfiguration)</sup>



## Customize Operation Tags (e.g. for UI Grouping)

The [OpenAPI specification][swagger-specification] allows one or more "tags" to be assigned to an operation. The OpenAPI generator
will assign the controller name as the default tag. This is important to note if you're using the `SwaggerUI` middleware as it uses this
value to group operations.

You can override the default tag by providing a function that applies tags by convention. For example, the following configuration will
tag, and therefore group operations in the UI, by HTTP method:



<a id='snippet-SwaggerGen-CustomTags'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.TagActionsBy(api => [api.HttpMethod]);
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L138-L143) | [anchor](#snippet-SwaggerGen-CustomTags)</sup>



## Change Operation Sort Order (e.g. for UI Sorting)

By default, actions are ordered by assigned tag (see above) before they're grouped into the path-centric, nested structure of the
[OpenAPI specification][swagger-specification]. However, you can change the default ordering of actions with a custom sorting strategy:



<a id='snippet-SwaggerGen-CustomSorting'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.OrderActionsBy((apiDesc) => $"{apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.HttpMethod}");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L145-L150) | [anchor](#snippet-SwaggerGen-CustomSorting)</sup>



> [!NOTE]
> This dictates the sort order **before** actions are grouped and transformed into the OpenAPI format. Therefore it affects the ordering
> of groups (i.e. OpenAPI "PathItems"), **and** the ordering of operations within a group, in the OpenAPI document that is output.

## Customize Schema Ids

If the generator encounters complex parameter or response types, it will generate a corresponding JSON schema, add it to the global
`components:schemas` dictionary, and reference it from the operation description by unique Id. For example, if you have an action
that returns a `Product` type, then the generated schema will be referenced as follows:

```yaml
responses: {
  200: {
    content: {
      "application/json": {
        schema: {
          $ref: "#/components/schemas/Product"
        }
      }
    }
  }
}
```

However, if it encounters multiple types with the same name but different namespaces (e.g. `RequestModels.Product` and `ResponseModels.Product`),
then Swashbuckle.AspNetCore will raise an exception due to _"Conflicting schemaIds"_. In this case, you'll need to provide a custom Id strategy that
further qualifies the name:



<a id='snippet-SwaggerGen-CustomSchemaIds'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.CustomSchemaIds((type) => type.FullName);
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L152-L157) | [anchor](#snippet-SwaggerGen-CustomSchemaIds)</sup>



> [!NOTE]
> See [this GitHub issue](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2703) for support for nested types.

## Override Schema for Specific Types

Out-of-the-box, Swashbuckle.AspNetCore performs a best-effort generating JSON schemas that accurately describe your request and response payloads.
However, if you're customizing serialization behavior for certain types in your API, you may need to help it out to get accurate output.

For example, you might have a class with multiple properties that you want to represent in JSON as a comma-separated string. To do this you
would probably implement a custom `JsonConverter`. In this case, Swashbuckle.AspNetCore doesn't know how the converter is implemented and so you would
need to provide it with a schema that accurately describes the type:

📝 `PhoneNumber.cs`



<a id='snippet-SwaggerGen-PhoneNumber'></a>
```cs
public class PhoneNumber
{
    public string CountryCode { get; set; } = string.Empty;

    public string AreaCode { get; set; } = string.Empty;

    public string SubscriberId { get; set; } = string.Empty;
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/PhoneNumber.cs#L3-L12) | [anchor](#snippet-SwaggerGen-PhoneNumber)</sup>



📝 `Startup.cs`



<a id='snippet-SwaggerGen-CustomSchemaMapping'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.MapType(() => new OpenApiSchema { Type = JsonSchemaType.String });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L159-L164) | [anchor](#snippet-SwaggerGen-CustomSchemaMapping)</sup>



## Extend Generator with Operation, Schema and Document Filters

Swashbuckle.AspNetCore exposes a filter pipeline that hooks into the generation process. Once generated, individual metadata objects are passed
into the pipeline where they can be modified further. You can wire up custom filters to enrich the generated `Operations`, `Schemas`
and `Documents`.

### Operation Filters

Swashbuckle.AspNetCore retrieves an `ApiDescription`, part of ASP.NET Core, for every action and uses it to generate a corresponding `OpenApiOperation`.
Once generated, it passes the `OpenApiOperation` and the `ApiDescription` through the list of configured Operation Filters.

In a typical filter implementation, you would inspect the `ApiDescription` for relevant information (e.g. route information, action attributes etc.)
and then update the `OpenApiOperation` accordingly. For example, the following filter lists an additional `401` response for all actions that
are decorated with `[Authorize]`:

📝 `AuthResponsesOperationFilter.cs`



<a id='snippet-SwaggerGen-AuthResponsesOperationFilter'></a>
```cs
public class AuthResponsesOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var hasAuthAttributes = context.MethodInfo.DeclaringType?.GetCustomAttributes(true)
            .Union(context.MethodInfo.GetCustomAttributes(true))
            .OfType<AuthorizeAttribute>()
            .Any() ?? false;

        if (hasAuthAttributes)
        {
            operation.Responses ??= [];
            operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
        }
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/AuthResponsesOperationFilter.cs#L7-L24) | [anchor](#snippet-SwaggerGen-AuthResponsesOperationFilter)</sup>



📝 `Startup.cs`



<a id='snippet-SwaggerGen-ConfigureOperationFilter'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.OperationFilter<AuthResponsesOperationFilter>();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L166-L171) | [anchor](#snippet-SwaggerGen-ConfigureOperationFilter)</sup>



> [!NOTE]
> Filter pipelines are DI-aware. That is, you can create filters with constructor parameters and if the parameter types
> are registered with the DI framework, they'll be automatically injected when the filters are instantiated.

### Schema Filters

Swashbuckle.AspnetCore generates an OpenAPI-flavored [JSONSchema](https://swagger.io/specification/#schema-object) for every parameter, response
and property type that's exposed by your endpoints. Once generated, it passes the schema and type through the list of configured
Schema Filters.

The example below adds an [AutoRest vendor extension](https://github.com/Azure/autorest/blob/main/docs/extensions/readme.md#x-ms-enum)
to inform the AutoRest tool how enums should be modelled when it generates the API client.

📝 `AutoRestSchemaFilter.cs`



<a id='snippet-SwaggerGen-AutoRestSchemaFilter'></a>
```cs
public class AutoRestSchemaFilter : ISchemaFilter
{
    public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
    {
        var type = context.Type;
        if (type.IsEnum && schema is OpenApiSchema concrete)
        {
            concrete.Extensions ??= new Dictionary<string, IOpenApiExtension>();
            concrete.Extensions.Add(
                "x-ms-enum",
                new JsonNodeExtension(
                    new JsonObject
                    {
                        ["name"] = type.Name,
                        ["modelAsString"] = true
                    }
                )
            );
        }
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/AutoRestSchemaFilter.cs#L7-L29) | [anchor](#snippet-SwaggerGen-AutoRestSchemaFilter)</sup>



📝 `Startup.cs`



<a id='snippet-SwaggerGen-ConfigureSchemaFilter'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.SchemaFilter<AutoRestSchemaFilter>();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L173-L178) | [anchor](#snippet-SwaggerGen-ConfigureSchemaFilter)</sup>



The example below allows for automatic schema generation of generic `Dictionary<Enum, TValue>` objects.
Note that this only generates the OpenAPI document; `System.Text.Json` is not able to parse dictionary enums by default,
so you will need [a special JsonConverter, as shown in the .NET documentation](https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/converters-how-to#sample-factory-pattern-converter).

📝 `DictionaryTKeyEnumTValueSchemaFilter.cs`



<a id='snippet-SwaggerGen-DictionaryTKeyEnumTValueSchemaFilter'></a>
```cs
public class DictionaryTKeyEnumTValueSchemaFilter : ISchemaFilter
{
    public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
    {
        if (schema is not OpenApiSchema concrete)
        {
            return;
        }

        // Only run for fields that are a Dictionary<Enum, TValue>
        if (!context.Type.IsGenericType || !context.Type.GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>)))
        {
            return;
        }

        var genericArgs = context.Type.GetGenericArguments();
        var keyType = genericArgs[0];
        var valueType = genericArgs[1];

        if (!keyType.IsEnum)
        {
            return;
        }

        concrete.Type = JsonSchemaType.Object;
        concrete.Properties = keyType.GetEnumNames().ToDictionary(
            name => name,
            name => context.SchemaGenerator.GenerateSchema(valueType, context.SchemaRepository));
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/DictionaryTKeyEnumTValueSchemaFilter.cs#L6-L37) | [anchor](#snippet-SwaggerGen-DictionaryTKeyEnumTValueSchemaFilter)</sup>



📝 `Startup.cs`



<a id='snippet-SwaggerGen-ConfigureSchemaFilterForEnumDictionaryEnum'></a>
```cs
services.AddSwaggerGen(options =>
{
    // These will be replaced by DictionaryTKeyEnumTValueSchemaFilter, but are needed to avoid
    // an error. You will need one for every kind of Dictionary<,> you have.
    options.MapType<Dictionary<MyEnum, List<string>>>(() => new OpenApiSchema());
    options.SchemaFilter<DictionaryTKeyEnumTValueSchemaFilter>();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L180-L188) | [anchor](#snippet-SwaggerGen-ConfigureSchemaFilterForEnumDictionaryEnum)</sup>



### Document Filters

Once an `OpenApiDocument` has been generated, it too can be passed through a set of pre-configured Document Filters.
This gives full control to modify the document however you see fit. To ensure you're still returning valid OpenAPI JSON, you
should have a read through the [specification][swagger-specification] before using this filter type.

The example below provides a description for any tags that are assigned to operations in the document:



<a id='snippet-SwaggerGen-TagDescriptionsDocumentFilter'></a>
```cs
public class TagDescriptionsDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        swaggerDoc.Tags = new HashSet<OpenApiTag>()
        {
            new() { Name = "Products", Description = "Browse/manage the product catalog" },
            new() { Name = "Orders", Description = "Submit orders" }
        };
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/TagDescriptionsDocumentFilter.cs#L6-L18) | [anchor](#snippet-SwaggerGen-TagDescriptionsDocumentFilter)</sup>



> [!NOTE]
> If you're using the `SwaggerUI` middleware, the `TagDescriptionsDocumentFilter` demonstrated above
> could be used to display additional descriptions beside each group of operations.

## Add Security Definitions and Requirements

In OpenAPI, you can describe how your API is secured by defining one or more security schemes (e.g. Basic, API key, OAuth2 etc.)
and declaring which of those schemes are applicable globally or for specific operations. For more details, take a look at the
[Security Requirement Object in the OpenAPI specification](https://swagger.io/specification/#security-requirement-object).

In Swashbuckle.AspNetCore, you can define schemes by invoking the `AddSecurityDefinition` method, providing a name and an instance of
`OpenApiSecurityScheme`. For example you can define an [OAuth 2.0 - implicit flow](https://oauth.net/2/) as follows:

📝 `Startup.cs`



<a id='snippet-SwaggerGen-AddSecurityDefinition'></a>
```cs
services.AddSwaggerGen(options =>
{
    // Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
    options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
    {
        Type = SecuritySchemeType.OAuth2,
        Flows = new OpenApiOAuthFlows
        {
            Implicit = new OpenApiOAuthFlow
            {
                AuthorizationUrl = new Uri("/auth-server/connect/authorize", UriKind.Relative),
                Scopes = new Dictionary<string, string>
                {
                    ["readAccess"] = "Access read operations",
                    ["writeAccess"] = "Access write operations"
                }
            }
        }
    });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L190-L211) | [anchor](#snippet-SwaggerGen-AddSecurityDefinition)</sup>



> [!NOTE]
> In addition to defining a scheme, you also need to indicate which operations that scheme is applicable to. You can apply schemes
> globally (i.e. to **all** operations) through the `AddSecurityRequirement` method. The example below indicates that the scheme called
> `"oauth2"` should be applied to all operations, and that the `"readAccess"` and `"writeAccess"` scopes are required. When applying
> schemes of type other than `"oauth2"`, the array of scopes **must** be empty.

📝 `Startup.cs`



<a id='snippet-SwaggerGen-AddSecurityRequirement'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.AddSecurityRequirement((document) => new OpenApiSecurityRequirement()
    {
        [new OpenApiSecuritySchemeReference("oauth2", document)] = ["readAccess", "writeAccess"]
    });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L213-L221) | [anchor](#snippet-SwaggerGen-AddSecurityRequirement)</sup>



If you have schemes that are only applicable for certain operations, you can apply them through an Operation filter. For
example, the following filter adds OAuth2 requirements based on the presence of the `AuthorizeAttribute`:

📝 `SecurityRequirementsOperationFilter.cs`



<a id='snippet-SwaggerGen-SecurityRequirementsOperationFilter'></a>
```cs
public class SecurityRequirementsOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        // Policy names map to scopes
        var requiredScopes = context.MethodInfo
            .GetCustomAttributes(true)
            .OfType<AuthorizeAttribute>()
            .Select(attribute => attribute.Policy!)
            .Distinct()
            .ToList();

        if (requiredScopes.Count > 0)
        {
            operation.Responses ??= [];
            operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
            operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });

            var scheme = new OpenApiSecuritySchemeReference("oauth2", context.Document);

            operation.Security =
            [
                new OpenApiSecurityRequirement
                {
                    [scheme] = requiredScopes
                }
            ];
        }
    }
}
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/SecurityRequirementsOperationFilter.cs#L7-L38) | [anchor](#snippet-SwaggerGen-SecurityRequirementsOperationFilter)</sup>



> [!NOTE]
> If you're using the `SwaggerUI` middleware, you can enable interactive OAuth2.0 flows that are powered by the emitted
> security metadata. See [Enabling OAuth2.0 Flows](configure-and-customize-swaggerui.md#enable-oauth20-flows) for more details.

## Add Security Definitions and Requirements for Bearer authentication



<a id='snippet-SwaggerGen-BearerAuthentication'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.AddSecurityDefinition("bearer", new OpenApiSecurityScheme
    {
        Type = SecuritySchemeType.Http,
        Scheme = "bearer",
        BearerFormat = "JWT",
        Description = "JWT Authorization header using the Bearer scheme."
    });
    options.AddSecurityRequirement(document => new OpenApiSecurityRequirement
    {
        [new OpenApiSecuritySchemeReference("bearer", document)] = []
    });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L223-L238) | [anchor](#snippet-SwaggerGen-BearerAuthentication)</sup>



## Inheritance and Polymorphism

OpenAPI defines the `allOf` and `oneOf` keywords for describing
[inheritance and polymorphism](https://swagger.io/docs/specification/v3_0/data-models/inheritance-and-polymorphism/#polymorphism) relationships
in schema definitions. For example, if you're using a base class for models that share common properties you can use the `allOf`
keyword to describe the inheritance hierarchy. Or, if your serializer supports polymorphic serialization/deserialization, you can use
the `oneOf` keyword to document all the "possible" schemas for requests/responses that vary by subtype.

### Enabling Inheritance

By default, Swashbuckle.AspNetCore flattens inheritance hierarchies. That is, for derived models, the inherited properties are combined and listed
alongside the declared properties. This can cause a lot of duplication in the generated OpenAPI document, particularly when there's multiple subtypes.
It's also problematic if you're using a client generator (e.g. NSwag) and would like to maintain the inheritance hierarchy in the generated
client models. To work around this, you can apply the `UseAllOfForInheritance` setting, and this will leverage the `allOf` keyword to
incorporate inherited properties by reference in the generated OpenAPI document:

```yaml
Circle: {
  type: "object",
  allOf: [
    {
      $ref: "#/components/schemas/Shape"
    }
  ],
  properties: {
    radius: {
      type: "integer",
      format: "int32",
    }
  },
},
Shape: {
  type: "object",
  properties: {
    name: {
      type: "string",
      nullable: true,
    }
  },
}
```

### Enabling Polymorphism

If your serializer supports polymorphic serialization/deserialization and you would like to list the possible subtypes for an action
that accepts/returns abstract base types, you can apply the `UseOneOfForPolymorphism` setting. As a result, the generated request/response
schemas will reference a collection of "possible" schemas instead of just the base class schema:

```json
"requestBody": {
  "content": {
    "application/json": {
      "schema": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/Rectangle"
          },
          {
            "$ref": "#/components/schemas/Circle"
          }
        ]
      }
    }
  }
}
```

### Detecting Subtypes

As inheritance and polymorphism relationships can often become quite complex, not just in your own models but also within the .NET class
library, Swashbuckle.AspNetCore is selective about which hierarchies it does and doesn't expose in the generated OpenAPI document. By default, it will
pick up any subtypes that are defined in the same assembly as a given base type. If you'd like to override this behavior, you can provide a
custom selector method:



<a id='snippet-SwaggerGen-DetectSubtypes'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.UseAllOfForInheritance();

    options.SelectSubTypesUsing(baseType =>
    {
        return typeof(Program).Assembly.GetTypes().Where(type => type.IsSubclassOf(baseType));
    });
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L240-L250) | [anchor](#snippet-SwaggerGen-DetectSubtypes)</sup>



> [!NOTE]
> If you're using the [Swashbuckle Annotations library](configure-and-customize-annotations.md#configuration--customization-of-swashbuckleaspnetcoreannotations), it
> contains a custom selector that's based on the presence of `[JsonDerivedType]` attributes on base class definitions. This
> way, you can use simple attributes to explicitly list the inheritance and/or polymorphism relationships you want to expose.
> To enable this behavior, check out the [Annotations docs](configure-and-customize-annotations.md#list-known-subtypes-for-inheritance-and-polymorphism).

### Describing Discriminators

In conjunction with the `oneOf` and/or `allOf` keywords, OpenAPI supports a `discriminator` field on base schema definitions.
This keyword points to the property that identifies the specific type being represented by a given payload. In addition to the property
name, the discriminator description may also include a `mapping` which maps discriminator values to specific schema definitions.

For example, the Newtonsoft serializer supports polymorphic serialization/deserialization by emitting/accepting a `"$type"` property on
JSON instances. The value of this property will be the [assembly qualified type name](https://learn.microsoft.com/dotnet/api/system.type.assemblyqualifiedname)
of the type represented by a given JSON instance. So, to explicitly describe this behavior in OpenAPI, the corresponding request/response
schema could be defined as follows:

```yaml
components: {
  schemas: {
    Shape: {
      required: [
        "$type"
      ],
      type: "object",
      properties: {
        $type: {
          type: "string"
        },
        discriminator: {
          propertyName: "$type",
          mapping: {
            Rectangle: "#/components/schemas/Rectangle",
            Circle: "#/components/schemas/Circle"
          }
        }
      }
    },
    Rectangle: {
      type: "object",
      allOf: [
        {
          "$ref": "#/components/schemas/Shape"
        }
      ],
      ...
    },
    Circle: {
      type: "object",
      allOf: [
        {
          "$ref": "#/components/schemas/Shape"
        }
      ],
      ...
    }
  }
}
```

If `UseAllOfForInheritance` or `UseOneOfForPolymorphism` is enabled, and your serializer supports (and has enabled) emitting/accepting
a discriminator property, then Swashbuckle will automatically generate the corresponding `discriminator` metadata on base schema definitions.

Alternatively, if you've customized your serializer to support polymorphic serialization/deserialization, you can provide some custom
selector functions to determine the discriminator name and corresponding mapping:



<a id='snippet-SwaggerGen-UseAllOfForInheritance'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.UseAllOfForInheritance();

    options.SelectDiscriminatorNameUsing((baseType) => "TypeName");
    options.SelectDiscriminatorValueUsing((subType) => subType.Name);
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L252-L260) | [anchor](#snippet-SwaggerGen-UseAllOfForInheritance)</sup>



> [!NOTE]
> If you're using the [Swashbuckle Annotations library](configure-and-customize-annotations.md#configuration--customization-of-swashbuckleaspnetcoreannotations), it
> contains custom selector functions that are based on the presence of `[JsonPolymorphic]` and `[JsonDerivedType]` attributes on base
> class definitions. This way, you can use simple attributes to explicitly provide discriminator metadata. To enable this behavior, check
> out the [Annotations documentation](configure-and-customize-annotations.md#enrich-polymorphic-base-classes-with-discriminator-metadata).

[swagger-specification]: https://swagger.io/specification/ "OpenAPI Specification"

---

## File: docs/configure-and-customize-swaggerui.md

# Configuration and Customization of `Swashbuckle.AspNetCore.SwaggerUI`

## Change Relative Path to the UI

By default, the Swagger UI will be exposed at `/swagger`. If necessary, you can alter this when enabling the SwaggerUI middleware:



<a id='snippet-SwaggerUI-CustomPath'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.RoutePrefix = "api-docs";
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L34-L39) | [anchor](#snippet-SwaggerUI-CustomPath)</sup>



## Change Document Title

By default, the Swagger UI will have a generic document title. When you have multiple OpenAPI documents open, it can be difficult to
tell them apart. You can alter this when enabling the SwaggerUI middleware:



<a id='snippet-SwaggerUI-CustomDocumentTitle'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.DocumentTitle = "My Swagger UI";
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L41-L46) | [anchor](#snippet-SwaggerUI-CustomDocumentTitle)</sup>



## Change CSS or JS Paths

By default, the Swagger UI includes default CSS and JavaScript, but if you wish to change the path or URL (for example to use a CDN)
you can override the defaults as shown below:



<a id='snippet-SwaggerUI-CustomAssets'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.StylesPath = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.29.1/swagger-ui.min.css";
    options.ScriptBundlePath = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.29.1/swagger-ui-bundle.min.js";
    options.ScriptPresetsPath = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.29.1/swagger-ui-standalone-preset.min.js";
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L48-L55) | [anchor](#snippet-SwaggerUI-CustomAssets)</sup>



## List Multiple OpenAPI Documents

When enabling the middleware, you're required to specify one or more OpenAPI endpoints (fully qualified or relative to the UI page) to
power the UI. If you provide multiple endpoints, they'll be listed in the top right corner of the page, allowing users to toggle between
the different documents. For example, the following configuration could be used to document different versions of an API.



<a id='snippet-SwaggerUI-MultipleDocuments'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs");
    options.SwaggerEndpoint("/swagger/v2/swagger.json", "V2 Docs");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L57-L63) | [anchor](#snippet-SwaggerUI-MultipleDocuments)</sup>



## Apply swagger-ui Parameters

[swagger-ui][swagger-ui] ships with its own set of configuration parameters, all described
[by the swagger-ui Configuration](https://github.com/swagger-api/swagger-ui/blob/HEAD/docs/usage/configuration.md#display).
In Swashbuckle.AspNetCore, most of these are surfaced through the SwaggerUI middleware options:



<a id='snippet-SwaggerUI-CustomOptions'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.DefaultModelExpandDepth(2);
    options.DefaultModelRendering(ModelRendering.Model);
    options.DefaultModelsExpandDepth(-1);
    options.DisplayOperationId();
    options.DisplayRequestDuration();
    options.DocExpansion(DocExpansion.None);
    options.EnableDeepLinking();
    options.EnableFilter();
    options.EnablePersistAuthorization();
    options.EnableTryItOutByDefault();
    options.MaxDisplayedTags(5);
    options.ShowExtensions();
    options.ShowCommonExtensions();
    options.EnableValidator();
    options.SupportedSubmitMethods(SubmitMethod.Get, SubmitMethod.Head);
    options.UseRequestInterceptor("(request) => { return request; }");
    options.UseResponseInterceptor("(response) => { return response; }");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L65-L86) | [anchor](#snippet-SwaggerUI-CustomOptions)</sup>



## Inject Custom JavaScript

To tweak the behavior, you can inject additional JavaScript files by adding them to your `wwwroot` folder and specifying
the relative paths in the middleware options:



<a id='snippet-SwaggerUI-JavaScript'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.InjectJavascript("/swagger-ui/custom.js");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L88-L93) | [anchor](#snippet-SwaggerUI-JavaScript)</sup>



## Inject Custom CSS

To tweak the look and feel, you can inject additional CSS stylesheets by adding them to your `wwwroot` folder and specifying the
relative paths in the middleware options:



<a id='snippet-SwaggerUI-CSS'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.InjectStylesheet("/swagger-ui/custom.css");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L95-L100) | [anchor](#snippet-SwaggerUI-CSS)</sup>



## Customize index.html

To customize the UI beyond the basic options listed above, you can provide your own version of the swagger-ui `index.html` page:



<a id='snippet-SwaggerUI-CustomIndexHtml'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.IndexStream = () => typeof(Program).Assembly
        .GetManifestResourceStream("CustomUIIndex.Swagger.index.html"); // Requires file to be added as an embedded resource
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L102-L108) | [anchor](#snippet-SwaggerUI-CustomIndexHtml)</sup>



```xml

  
    
  

```

> [!TIP]
> To get started, you should base your custom `index.html` on the [built-in version](../src/Swashbuckle.AspNetCore.SwaggerUI/index.html).

## Enable OAuth2.0 Flows

[swagger-ui][swagger-ui] has built-in support to participate in OAuth2.0 authorization flows. It interacts with authorization and/or token
endpoints, as specified in the OpenAPI JSON, to obtain access tokens for subsequent API calls. See
[Adding Security Definitions and Requirements](configure-and-customize-swaggergen.md#add-security-definitions-and-requirements) for
an example of adding OAuth2.0 metadata to the generated Swagger.

If your OpenAPI endpoint includes the appropriate security metadata, the UI interaction should be automatically enabled. However, you
can further customize OAuth support in the UI with the following settings below. See the
[Swagger-UI documentation](https://github.com/swagger-api/swagger-ui/blob/HEAD/docs/usage/oauth2.md) for more information.



<a id='snippet-SwaggerUI-OAuth2'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.OAuthClientId("test-id");
    options.OAuthClientSecret("test-secret");
    options.OAuthUsername("test-user");
    options.OAuthRealm("test-realm");
    options.OAuthAppName("test-app");
    options.OAuth2RedirectUrl("url");
    options.OAuthScopeSeparator(" ");
    options.OAuthScopes("scope1", "scope2");
    options.OAuthAdditionalQueryStringParams(new Dictionary<string, string> { ["foo"] = "bar" });
    options.OAuthUseBasicAuthenticationWithAccessCodeGrant();
    options.OAuthUsePkce();
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L110-L125) | [anchor](#snippet-SwaggerUI-OAuth2)</sup>



## Use client-side request and response interceptors

To use custom interceptors on requests and responses going through swagger-ui you can define them as JavaScript functions
in the configuration:



<a id='snippet-SwaggerUI-Interceptors'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.UseRequestInterceptor("(req) => { req.headers['x-my-custom-header'] = 'MyCustomValue'; return req; }");
    options.UseResponseInterceptor("(res) => { console.log('Custom interceptor intercepted response from:', res.url); return res; }");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L127-L133) | [anchor](#snippet-SwaggerUI-Interceptors)</sup>



This can be useful in a range of scenarios where you might want to append local XSRF tokens to all requests, for example:



<a id='snippet-SwaggerUI-Interceptor-XSRF'></a>
```cs
app.UseSwaggerUI(options =>
{
    options.UseRequestInterceptor("(req) => { req.headers['X-XSRF-Token'] = localStorage.getItem('xsrf-token'); return req; }");
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L135-L140) | [anchor](#snippet-SwaggerUI-Interceptor-XSRF)</sup>



## Use `MapSwaggerUI` with endpoint routing

`MapSwaggerUI` is an endpoint-routing alternative to `UseSwaggerUI`. The options API is the same, so all customization examples on this page also apply when using `MapSwaggerUI`.



<a id='snippet-SwaggerUI-MapSwaggerUI'></a>
```cs
app.MapSwagger();
app.MapSwaggerUI("swagger", options => options.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs"));
```
<sup>[snippet source](/test/WebSites/WebApi.Map/Program.cs#L21-L24) | [anchor](#snippet-SwaggerUI-MapSwaggerUI)</sup>



The main differences are:

- **Use**SwaggerUI adds middleware directly to the request pipeline and returns `IApplicationBuilder`.
- **Map**SwaggerUI maps the Swagger UI via endpoint routing and returns `IEndpointConventionBuilder`.

- Because `MapSwaggerUI` returns an endpoint convention builder, you can attach endpoint metadata/conventions (for example, authorization policies) directly to the mapped UI endpoint.



<a id='snippet-SwaggerUI-MapSwaggerUI-RequireAuthorization'></a>
```cs
app.MapSwaggerUI("swagger-auth")
   .RequireAuthorization(); // Remember to also add RequireAuthorization to MapSwagger.
```
<sup>[snippet source](/test/WebSites/WebApi.Map/Program.cs#L26-L29) | [anchor](#snippet-SwaggerUI-MapSwaggerUI-RequireAuthorization)</sup>



[swagger-ui]: https://github.com/swagger-api/swagger-ui

---

## File: docs/migrating-to-v10.md

# 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)][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 reason, ASP.NET Core v10+ also depends on Microsoft.OpenApi v2+ if you use the [Microsoft.AspNetCore.OpenApi][microsoft-aspnetcore-openapi-package]
NuGet package, 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.



<a id='snippet-Swagger-OpenAPI3.1'></a>
```cs
app.UseSwagger(options =>
{
    options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
});
```
<sup>[snippet source](/test/WebSites/DocumentationSnippets/WebApplicationExtensions.cs#L218-L223) | [anchor](#snippet-Swagger-OpenAPI3.1)</sup>



## How do I migrate to Swashbuckle.AspNetCore v10+?

> [!TIP]
> It is strongly recommended that you upgrade to [Swashbuckle.AspNetCore v9.0.6][swashbuckle-aspnetcore-906] **before** upgrading to 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.0.0+ and v2.3.0+ 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 use the relevant concrete types to mutate them (e.g. `OpenApiSchema`). An example of this is shown below for an `ISchemaFilter` implementation:

   ```csharp
  public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
  {
       if (schema is OpenApiSchema openApiSchema)
       {
            // The properties are only mutable on the concrete type
            openApiSchema.Type = JsonSchemaType.String;
       }
   }     
   ```

- 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][microsoft-aspnetcore-openapi-package].
- Updating any use of `AddSecurityRequirement()` to use a `Func<OpenApiDocument, OpenApiSecurityRequirement>` ([documentation][security]).
- Updating some collections to use specific concrete types instead of interfaces if collection expressions were used, for example using `HashSet<OpenApiTag>` with `OpenApiDocument.Tags` which is now an `ISet<OpenApiTag>`.

[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-aspnetcore-openapi-package]: https://www.nuget.org/packages/Microsoft.AspNetCore.OpenApi/ "Microsoft.AspNetCore.OpenApi NuGet package"
[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"
[security]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/v10.0.0/docs/configure-and-customize-swaggergen.md#add-security-definitions-and-requirements "Add Security Definitions and Requirements"
[semver]: https://semver.org/ "Semantic Versioning 2.0.0"
[swashbuckle-aspnetcore-906]: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases/tag/v9.0.6 "Swashbuckle.AspNetCore v9.0.6"
[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"