Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 = ["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
9 changes: 9 additions & 0 deletions test/WebSites/CustomUIConfig/wwwroot/ext/custom-plugin1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
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 {
};
};
9 changes: 9 additions & 0 deletions test/WebSites/CustomUIConfig/wwwroot/ext/custom-plugin2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
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 {
};
};