Skip to content

Latest commit

 

History

History
329 lines (281 loc) · 13 KB

File metadata and controls

329 lines (281 loc) · 13 KB

Configuration and Customization of Swashbuckle.AspNetCore.Annotations

Install and Enable Annotations

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

dotnet add package Swashbuckle.AspNetCore.Annotations

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

services.AddSwaggerGen(options =>
{
    // Other setup, then...
    options.EnableAnnotations();
});

snippet source | anchor

Enrich Operation Metadata

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

[HttpPost]
[SwaggerOperation(
    Summary = "Creates a new product",
    Description = "Requires admin privileges",
    OperationId = "CreateProduct",
    Tags = ["Purchase", "Products"]
)]
public IActionResult Create([FromBody] Product product)
{
    //...
    return Ok();
}

snippet source | anchor

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

[HttpPost]
[SwaggerResponse(201, "The product was created", typeof(Product))]
[SwaggerResponse(400, "The product data is invalid")]
public IActionResult Post([FromBody] Product product)
{
    //...
    return Created();
}

snippet source | anchor

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:

[HttpGet]
public IActionResult GetProducts(
    [FromQuery, SwaggerParameter("Search keywords", Required = true)] string keywords)
{
    //...
    return Ok();
}

snippet source | anchor

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:

[HttpPost]
public IActionResult SubmitProduct(
    [FromBody, SwaggerRequestBody("The product payload", Required = true)] Product product)
{
    //...
    return Created();
}

snippet source | anchor

Enrich Schema Metadata

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

[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; }
}

snippet source | anchor

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

[SwaggerSchemaFilter(typeof(ItemSchemaFilter))]
public class Item
{
    //...
}

snippet source | anchor

📝 ItemSchemaFilter.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"
            };
        }
    }
}

snippet source | anchor

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. 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]:

[SwaggerTag("Create, read, update and delete Items")]
public class ItemsController
{
    //...
}

snippet source | anchor

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, 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

services.AddSwaggerGen(options =>
{
    options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});

snippet source | anchor

📝 Shape.cs

[JsonDerivedType(typeof(Rectangle))]
[JsonDerivedType(typeof(Circle))]
public abstract class Shape
{
}

snippet source | anchor

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

services.AddSwaggerGen(options =>
{
    options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true);
});

snippet source | anchor

📝 ShapeWithDiscriminator.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
}

snippet source | anchor

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:

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