简体   繁体   中英

Does Swashbuckle support a way to represent custom operation tags as badges in the UI?

I'm developing an ASP.NET Core application and there are some endpoints that I want to tag as "developer tool", indicating that these endpoints exist purely for the benefit of the development team to take investigative/corrective action and are not intended for third-party consumption. Something like this:

在此处输入图像描述

I've checked the Swashbuckle repo and can't find anything to suggest this is supported, but I thought it's best to check.

Since there doesn't seem to be built-in way to do this, I managed to achieve this result through a pretty hacky (but effective) approach of using an operation filter to append text to the operation summary in a particular format and then injecting custom CS/JSS that converts these parts of the summary description into custom elements in the DOM.

First I define a custom attribute:

/// <summary>
/// Indicates that this operation is intended for use solely by the development team.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class DeveloperToolAttribute : Attribute
{
}

Then I create an operation filter to process these:

public class DeveloperToolOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (!context.ApiDescription.CustomAttributes().Any(x => x is DeveloperToolAttribute))
            return;

        operation.Summary = $"[Developer Tool] {operation.Summary}";
    }
}

I register this filter after the other filters that set the operation summary based on the XML documentation:

services.AddSwaggerGen(options =>
{
    // ...

    void AddXmlDocumentation(Assembly assembly)
    {
        var xmlFile = $"{assembly.GetName().Name}.xml";
        var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
        options.IncludeXmlComments(xmlPath, includeControllerXmlComments: true);
    }

    // Set the comments path for the Swagger JSON and UI.
    AddXmlDocumentation(Assembly.GetExecutingAssembly());
    AddXmlDocumentation(typeof(StatementReadModel).Assembly);
    // ...
    options.OperationFilter<DeveloperToolOperationFilter>();
});

This would then make it so that I could annotate my API methods with [DeveloperTool] and have that become part of the operation summary:

[HttpGet]
[DeveloperTool]
public async Task<CommissionAuthorisationsReadModel> GetAuthorisations()
{
    var result = await _mediator.Send(CommissionAuthorisationsQuery.Instance);

    return result;
}

在此处输入图像描述

Next up I used TamperMonkey to build a userscript that allowed me to iterate through all the DOM elements containing these operation summaries and transform any text within braces (such as [Developer Tool] ) into badges.

This allowed me to produce the following Javascript file which I saved as wwwroot/ext/custom-swagger-javascript.js :

var callback = function() {
    var elements = document.getElementsByClassName("opblock-summary-description");

    for (const summaryDescription of elements) {
        const match = summaryDescription.textContent.match(/\[(\w|\s)+\]\s/);
    
        if (!match) {
            continue;
        }

        const trimmedTextContent = summaryDescription.textContent.replaceAll(match[0], "");
        summaryDescription.textContent = trimmedTextContent;

        const customTag = match[0].substring(1, match[0].length - 2);
        const summary = summaryDescription.parentElement;
        const customTagElement = document.createElement("div");

        customTagElement.innerText = customTag;
        customTagElement.className = "opblock-custom-tag";
        summary.appendChild(customTagElement);
    }
};

// Repeat just in case page is slow to load.
for (let attempts = 1; attempts <= 5; attempts++) {
    setTimeout(callback, attempts * 200);
}

Alongside this I created a CSS stylesheet saved as wwwroot/ext/custom-swagger-stylesheet.css :

.opblock-custom-tag {
    font-size: 10px;
    font-weight: 700;
    min-width: 80px;
    padding: 6px 15px;
    text-align: center;
    border-radius: 3px;
    background: #9d45d4;
    text-shadow: 0 1px 0 rgba(0,0,0,.1);
    font-family: sans-serif;
    color: #fff;
}

In Startup, I ensured that these Javascript and CSS files would be injected:

app.UseSwaggerUI(c =>
{
    // ...
    
    c.InjectStylesheet("/ext/custom-swagger-stylesheet.css");
    c.InjectJavascript("/ext/custom-swagger-javascript.js");
});

This also required me to ensure that ASP.NET Core would serve static files:

app.UseHttpsRedirection();
app.UseStaticFiles(); // Added this
app.UseRouting();

Finally this all allowed me to get the result that I wanted:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM