# 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:

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-Enable -->
<a id='snippet-Annotations-Enable'></a>
```cs
services.AddSwaggerGen(options =>
{
    // Other setup, then...
    options.EnableAnnotations();
});
```
<sup><a href='/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L27-L33' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-Enable' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

## Enrich Operation Metadata

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

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-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><a href='/test/WebSites/DocumentationSnippets/ProductsController.cs#L24-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SwaggerOperation' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

## 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:

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-SwaggerResponse -->
<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><a href='/test/WebSites/DocumentationSnippets/ProductsController.cs#L39-L48' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SwaggerResponse' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

## 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:

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-SwaggerParameter -->
<a id='snippet-Annotations-SwaggerParameter'></a>
```cs
[HttpGet]
public IActionResult GetProducts(
    [FromQuery, SwaggerParameter("Search keywords", Required = true)] string keywords)
{
    //...
    return Ok();
}
```
<sup><a href='/test/WebSites/DocumentationSnippets/ProductsController.cs#L50-L58' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SwaggerParameter' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

## 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:

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-SwaggerRequestBody -->
<a id='snippet-Annotations-SwaggerRequestBody'></a>
```cs
[HttpPost]
public IActionResult SubmitProduct(
    [FromBody, SwaggerRequestBody("The product payload", Required = true)] Product product)
{
    //...
    return Created();
}
```
<sup><a href='/test/WebSites/DocumentationSnippets/ProductsController.cs#L60-L68' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SwaggerRequestBody' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

## Enrich Schema Metadata

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

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-SwaggerSchema -->
<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><a href='/test/WebSites/DocumentationSnippets/Product.cs#L5-L18' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SwaggerSchema' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

> [!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`

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-SchemaModel -->
<a id='snippet-Annotations-SchemaModel'></a>
```cs
[SwaggerSchemaFilter(typeof(ItemSchemaFilter))]
public class Item
{
    //...
}
```
<sup><a href='/test/WebSites/DocumentationSnippets/Item.cs#L5-L11' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SchemaModel' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

📝 `ItemSchemaFilter.cs`

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-SchemaFilter -->
<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><a href='/test/WebSites/DocumentationSnippets/ItemSchemaFilter.cs#L7-L22' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SchemaFilter' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

## 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]`:

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-SwaggerTag -->
<a id='snippet-Annotations-SwaggerTag'></a>
```cs
[SwaggerTag("Create, read, update and delete Items")]
public class ItemsController
{
    //...
}
```
<sup><a href='/test/WebSites/DocumentationSnippets/ItemsController.cs#L5-L11' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-SwaggerTag' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

> [!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`

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-EnablePolymorphism -->
<a id='snippet-Annotations-EnablePolymorphism'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});
```
<sup><a href='/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L35-L40' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-EnablePolymorphism' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

📝 `Shape.cs`

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-Shape -->
<a id='snippet-Annotations-Shape'></a>
```cs
[JsonDerivedType(typeof(Rectangle))]
[JsonDerivedType(typeof(Circle))]
public abstract class Shape
{
}
```
<sup><a href='/test/WebSites/DocumentationSnippets/Shape.cs#L5-L11' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-Shape' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

## 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`

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-EnablePolymorphism -->
<a id='snippet-Annotations-EnablePolymorphism'></a>
```cs
services.AddSwaggerGen(options =>
{
    options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});
```
<sup><a href='/test/WebSites/DocumentationSnippets/IServiceCollectionExtensions.cs#L35-L40' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-EnablePolymorphism' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

📝 `ShapeWithDiscriminator.cs`

<!-- markdownlint-disable MD031 MD033 -->
<!-- snippet: Annotations-ShapeWithDiscriminator -->
<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><a href='/test/WebSites/DocumentationSnippets/ShapeWithDiscriminator.cs#L5-L22' title='Snippet source file'>snippet source</a> | <a href='#snippet-Annotations-ShapeWithDiscriminator' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
<!-- markdownlint-enable MD031 MD033 -->

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",
    }
  }
}
```
