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.