Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1302,13 +1302,17 @@ app.UseSwaggerUI(c =>
c.MaxDisplayedTags(5);
c.ShowExtensions();
c.ShowCommonExtensions();
c.Plugins = new string[]{"myCustomPlugin"}
c.EnableValidator();
c.SupportedSubmitMethods(SubmitMethod.Get, SubmitMethod.Head);
c.UseRequestInterceptor("(request) => { return request; }");
c.UseResponseInterceptor("(response) => { return response; }");
});
```

> [!NOTE]
> When adding custom plugins, make sure you add any custom `js` files that define the plugin function(s).

### Inject Custom JavaScript ###

To tweak the behavior, you can inject additional JavaScript files by adding them to your `wwwroot` folder and specifying the relative paths in the middleware options:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Swashbuckle.AspNetCore.SwaggerUI.ConfigObject.Plugins.get -> System.Collections.Generic.IList<string>
Swashbuckle.AspNetCore.SwaggerUI.ConfigObject.Plugins.set -> void
6 changes: 6 additions & 0 deletions src/Swashbuckle.AspNetCore.SwaggerUI/SwaggerUIOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ public class ConfigObject
[JsonPropertyName("validatorUrl")]
public string ValidatorUrl { get; set; } = null;

/// <summary>
/// Any custom plugins' function names.
/// </summary>
[JsonPropertyName("plugins")]
public IList<string> Plugins { get; set; } = null;

[JsonExtensionData]
public Dictionary<string, object> AdditionalItems { get; set; } = [];
}
Expand Down
4 changes: 4 additions & 0 deletions src/Swashbuckle.AspNetCore.SwaggerUI/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ window.onload = function () {
if (interceptors.ResponseInterceptorFunction)
configObject.responseInterceptor = parseFunction(interceptors.ResponseInterceptorFunction);

if (configObject.plugins) {
configObject.plugins = configObject.plugins.map(eval);
}

// Begin Swagger UI call region

const ui = SwaggerUIBundle(configObject);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -74,6 +75,29 @@ public async Task SwaggerUIMiddleware_ReturnsInitializerScript(
Assert.DoesNotContain("%(Interceptors)", jsContent);
}

[Fact]
public async Task IndexUrl_DefinesPlugins()
{
var client = new TestSite(typeof(CustomUIConfig.Startup)).BuildClient();

var jsResponse = await client.GetAsync("/swagger/index.js");
Assert.Equal(HttpStatusCode.OK, jsResponse.StatusCode);

var jsContent = await jsResponse.Content.ReadAsStringAsync();
Assert.Contains($"\"plugins\":[\"customPlugin1\",\"customPlugin2\"]", jsContent);
}

[Fact]
public async Task IndexUrl_DoesntDefinePlugins()
{
var client = new TestSite(typeof(Basic.Startup)).BuildClient();

var jsResponse = await client.GetAsync("/index.js");
Assert.Equal(HttpStatusCode.OK, jsResponse.StatusCode);
var jsContent = await jsResponse.Content.ReadAsStringAsync();
Assert.DoesNotContain("\"plugins\"", jsContent);
}

[Fact]
public async Task IndexUrl_ReturnsCustomPageTitleAndStylesheets_IfConfigured()
{
Expand Down
6 changes: 5 additions & 1 deletion test/WebSites/CustomUIConfig/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,18 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
// Other
c.DocumentTitle = "CustomUIConfig";
c.StylesPath = "/ext/custom-stylesheet.css";
c.InjectStylesheet("/ext/custom-stylesheet.css");
c.ScriptBundlePath = "/ext/custom-javascript.js";
c.ScriptPresetsPath = "/ext/custom-javascript.js";
c.InjectStylesheet("/ext/custom-stylesheet.css");
c.InjectJavascript("/ext/custom-javascript.js");
c.InjectJavascript("/ext/custom-plugin1.js");
c.InjectJavascript("/ext/custom-plugin2.js");
c.UseRequestInterceptor("(req) => { req.headers['x-my-custom-header'] = 'MyCustomValue'; return req; }");
c.UseResponseInterceptor("(res) => { console.log('Custom interceptor intercepted response from:', res.url); return res; }");
c.EnablePersistAuthorization();

c.ConfigObject.Plugins = ["customPlugin1", "customPlugin2"];

c.ConfigObject.AdditionalItems.Add("syntaxHighlight", false);
c.ConfigObject.AdditionalItems.Add("charProperty", 'c');
c.ConfigObject.AdditionalItems.Add("stringProperty", "value");
Expand Down
10 changes: 10 additions & 0 deletions test/WebSites/CustomUIConfig/wwwroot/ext/custom-plugin1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

const customPlugin1 = function (system) {
var elem = document.createElement("div");
elem.innerHTML =
"<div style=\"text-align: center; font-family: Titillium Web,sans-serif; margin: 16px;\">This text was injected via /ext/custom-plugin1.js, using the SwaggerUIOptions.Plugins method.</div>";

document.body.insertBefore(elem, document.body.firstChild);
return {
};
};
10 changes: 10 additions & 0 deletions test/WebSites/CustomUIConfig/wwwroot/ext/custom-plugin2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

const customPlugin2 = function (system) {
var elem = document.createElement("div");
elem.innerHTML =
"<div style=\"text-align: center; font-family: Titillium Web,sans-serif; margin: 16px;\">This text was injected via /ext/custom-plugin2.js, using the SwaggerUIOptions.Plugins method.</div>";

document.body.insertBefore(elem, document.body.firstChild);
return {
};
};