3 Tips to Elevate your Swagger UI

August 10 2024

 

Many thanks to the sponsors who make it possible for this newsletter to be free for readers.

 

• Transform your API development process with Postman Flows! Experience a new way to visually create, debug, and automate complex API workflows with ease. Dive into the future of API management and enhance your productivity here.

 

• Create a production-ready Blazor application from start to finish with the latest edition of Web Development with Blazor by Jimmy Engstrom. You can learn more here.

 
 

We know Swagger is a set of tools for developing, documenting, and consuming RESTful APIs. It helps developers design, build, document, and consume APIs more efficient.

 

Swashbuckle is an open-source project that integrates Swagger with .NET applications. It provides seamless support for generating Swagger documents and exposing them via a web interface in ASP.NET Core applications.

 

By default, when an API project is created, code is generated in Program.cs that will create the Swagger support, along with the Swagger UI.

builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

 

This UI is quite "clean" and it is possible to enrich it with many things.

Swagger UI Demo  

I will show you 1 tip of what can be done with Swagger UI.

 
 

IDocumentFilter interface

 
 

The IDocumentFilter interface in Swashbuckle is a powerful feature that allows you to manipulate and customize the entire Swagger/OpenAPI document before it is rendered or served to clients.

 

This interface provides a hook into the Swagger generation process, giving you the ability to modify, add, or remove any part of the document, such as paths, operations, schemas, and more.

 

Implementation

 

To use IDocumentFilter, you need to create a class that implements this interface and its Apply method.

 

The Apply method provides access to the OpenApiDocument object, which represents the entire Swagger document, and the DocumentFilterContext object, which provides additional context and information.

 

For example, let's create a case where you need to remove an obsolete (deprecated) endpoint from Swagger UI and not delete it from the code.

 

Firstly, if we tag some endpoint as obsolete, this will not hide it from Swagger UI. It will be just crossed and grayed out.

Swagger UI Obsolete Endpoint

 

To be able to delete it, I will create RemoveObsoleteOperationsFilter implementation of IDocumentFilter abstraction.

public class RemoveObsoleteOperationsFilter : IDocumentFilter {
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) {
        var obsoletePaths = swaggerDoc.Paths
            .Where(path => path.Value.Operations
                .Any(op => op.Value.Deprecated))
            .Select(path => path.Key)
            .ToList();

        foreach (var obsoletePath in obsoletePaths)
            swaggerDoc.Paths.Remove(obsoletePath);
        }
}

 

I need to add a support for this DocumentFilter. It's really to add it, just update the .AddSwaggerGen() method call in Program.cs:

builder.Services.AddSwaggerGen(c =>
{
    c.DocumentFilter<RemoveObsoleteOperationsFilter>();
});

 

And now, the endpoint is removed from the Swagger UI.

 
 

2 more examples of implementation IDocumentFiler abstraction

 
 

Adding Global Metadata to All Operations

 

Adding global metadata to all operations using an IDocumentFilter allows you to enforce consistent metadata across your entire API.

 

This can be particularly useful for ensuring that every operation has a baseline description, common tags for categorization, or other shared metadata.

 

By implementing and registering a custom document filter, you can automate these modifications, making your API documentation more uniform and easier to manage.

public class AddGlobalMetadataDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        foreach (var pathItem in swaggerDoc.Paths.Values)
        {
            foreach (var operation in pathItem.Operations.Values)
            {
                // Add a common description to all operations
                operation.Description = operation.Description ?? "This is a common description for all operations.";
                
                // Add a common tag to all operations
                operation.Tags = operation.Tags ?? new List<OpenApiTag>();
                operation.Tags.Add(new OpenApiTag { Name = "CommonTag" });
            }
        }
    }
}

 

Result:

Swagger UI Global Metadata

 

Adding a Custom Header to All Responses

 

Adding a custom header to all responses using an IDocumentFilter allows you to ensure that every API response includes specific metadata.

 

By implementing and registering a custom document filter, you can automate the inclusion of this header across all API endpoints, making your API documentation more comprehensive and consistent.

 

This approach is particularly useful for enforcing standard headers for purposes such as rate limiting, request tracking, or any other cross-cutting concerns.

public class AddCustomHeaderToResponsesDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        foreach (var pathItem in swaggerDoc.Paths.Values)
        {
            foreach (var operation in pathItem.Operations.Values)
            {
                foreach (var response in operation.Responses.Values)
                response.Headers ??= new Dictionary<string, OpenApiHeader>();
                
                response.Headers.Add("X-Custom-Header", new OpenApiHeader
                {
                    Description = "This is a custom header added to all responses.",
                    Schema = new OpenApiSchema
                    {
                        Type = "string"
                    }
                });
            }
            }
        }
    }
}

 

Result:

Swagger UI Custom Header  

In Program.cs you need to add those 2 DocumentFilters: a strategy object to perform the travel time calculation, allowing the strategy to be set dynamically.

 
 

Wrapping up

 
 

Swagger UI itself is "clean" at the beginning of the implementation.

 

We often need some advanced things, such as not showing deprecated endpoints, adding metadata, adding headers, changing responses, and similar.

 

Fortunately, it is possible to enrich Swagger UI to such levels that it is possible to change the complete design.

 

The Swashbuckle Library helps us with all of this.

 

Using the IDocumentationFILter abstraction, we created 3 implementations:

 

1. RemoveObsoleteOperationsFilter
2. AddGlobalMetadataDocumentFilter
3. AddCustomHeaderToResponsesDocumentFilter

 

For a deeper understanding and different implementations check out here.

 

You can download this source code from here.

 

That's all from me today.

Join 13,250+ subscribers to improve your .NET Knowledge.

There are 3 ways I can help you:

Design Patterns Simplified ebook

Go-to resource for understanding the core concepts of design patterns without the overwhelming complexity. In this concise and affordable ebook, I've distilled the essence of design patterns into an easy-to-digest format. It is a Beginner level. Check out it here.


Sponsorship

Promote yourself to 13,250+ subscribers by sponsoring this newsletter.


Join TheCodeMan.net Newsletter

Every Monday morning, I share 1 actionable tip on C#, .NET & Arcitecture topic, that you can use right away.


Subscribe to
TheCodeMan.net

Subscribe to the TheCodeMan.net and be among the 13,250+ subscribers gaining practical tips and resources to enhance your .NET expertise.