Search code examples
c#swaggerswagger-uiswashbuckle

Exposing a Schema that is not exposed by default with Swagger


Swagger exposes by default any schema that is used by an exposed controller (API end point). How can a schema (class) be exposed if it is not used by a controller?

For example, Swagger is showing the following Schemas:

Swagger Schemas

But, the Song Schema (below) needs to be exposed. It is not exposed because it is not used by a controller (API end point).

using System;
namespace ExampleNamespace
{
    public class Song
    {
        [Key][Required]
        public int SongID { get; set; }
        [Required]
        public string SongName { get; set; }
        public string SongDescription { get; set; }
        public int SongLength { get; set; } //seconds
        [Required]
        public int AlbumID { get; set; }
    }
}

How can this be accomplished?


Solution

  • You can add a schema using a DocumentFilter

    public class AddSongSchemaDocumentFilter : IDocumentFilter
    {
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            var songSchema = new OpenApiSchema {...};
            songSchema.Properties.Add(new KeyValuePair<string, OpenApiSchema>("songName", new OpenApiSchema { ... }));
            ...
    
            context.SchemaRepository.Schemas.Add("Song", songSchema);
        }
    }
    

    The class OpenApiSchema is used for the song schema itself, and for property schemas. This type contains a number of documentation related properties you can set such as Description.

    You register AddSongSchemaDocumentFilter like so

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSwaggerGen(options =>
        {
            options.DocumentFilter<AddSongSchemaDocumentFilter>();
        });
    }
    

    This could be a bit tedious if there are many properties. Using reflection, you can iterate on the properties, and even reflect on associated attributes attached to those properties.

    var songSchema = new OpenApiSchema() { };
    var song = new Song();
    var properties = typeof(Song).GetProperties();
    
    foreach (var p in properties)
        songSchema.Properties.Add(new KeyValuePair<string, OpenApiSchema(
            p.Name,
            new OpenApiSchema()
            {
                Type = p.PropertyType.ToString(),
                Description = // get [Description] attribute from p,
                // ... etc. for other metadata such as an example if desired
            }));
    
    context.SchemaRepository.Schemas.Add("Song", songSchema);
    

    Full Swashbuckle documentation.