Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add possibility to hook into the config initialization. #2590

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ The steps described above will get you up and running with minimal setup. Howeve
* [Customize index.html](#customize-indexhtml)
* [Enable OAuth2.0 Flows](#enable-oauth20-flows)
* [Use client-side request and response interceptors](#use-client-side-request-and-response-interceptors)
* [Change Swagger UI Config](#change-swagger-ui-config)

* [Swashbuckle.AspNetCore.Annotations](#swashbuckleaspnetcoreannotations)
* [Install and Enable Annotations](#install-and-enable-annotations)
Expand Down Expand Up @@ -1265,7 +1266,7 @@ app.UseSwaggerUI(c =>
});
```

_NOTE: The `InjectOnCompleteJavaScript` and `InjectOnFailureJavaScript` options have been removed because the latest version of swagger-ui doesn't expose the necessary hooks. Instead, it provides a [flexible customization system](https://github.com/swagger-api/swagger-ui/blob/master/docs/customization/overview.md) based on concepts and patterns from React and Redux. To leverage this, you'll need to provide a custom version of index.html as described [below](#customize-indexhtml)._
_NOTE: The `InjectOnCompleteJavaScript` and `InjectOnFailureJavaScript` options have been removed because the latest version of swagger-ui doesn't expose the necessary hooks. Instead, it provides a [flexible customization system](https://github.com/swagger-api/swagger-ui/blob/master/docs/customization/overview.md) based on concepts and patterns from React and Redux. To leverage this, adjust the [configuration initialization with plugins](#change-swagger-ui-config) or you'll need to provide a custom version of index.html as described [below](#customize-indexhtml)._

The [custom index sample app](test/WebSites/CustomUIIndex/Swagger/index.html) demonstrates this approach, using the swagger-ui plugin system provide a custom topbar, and to hide the info component.

Expand Down Expand Up @@ -1341,6 +1342,78 @@ app.UseSwaggerUI(c =>
});
```

### Change Swagger UI Config ###

Swagger UI has a big variety of options and a mighty plugin API allowing customizations.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Swagger UI has a big variety of options and a mighty plugin API allowing customizations.
Swagger UI has a large variety of options and a mighty plugin API allowing customizations.

To customize the Swagger UI (and OAuth) configuration objects before they are passed into the Swagger UI initialization,
inject a custom JavaScript file which defines a global function with the following signature.
In many cases this feature allows to avoid using a custom `index.html` in your project.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In many cases this feature allows to avoid using a custom `index.html` in your project.
In many cases this feature allows you to avoid using a custom `index.html` in your project.


```js
/**
* @param configObject See https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
* @param oauthConfigObject See https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/
*/
function initConfig(configObject, oauthConfigObject) { }
```

Through this mechanism any options that Swagger UI supports can be set and also plugins can be registered.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Through this mechanism any options that Swagger UI supports can be set and also plugins can be registered.
Through this mechanism any options that Swagger UI supports can be set, and also plugins can be registered.

Swagger UI is written with React so it can be a bit tricky to write custom components.
Here a full example which adds a custom section to the parameters of all operations:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Here a full example which adds a custom section to the parameters of all operations:
Here is a full example which adds a custom section to the parameters of all operations:


```js
// swagger-ui.js
// https://swagger.io/docs/open-source-tools/swagger-ui/customization/plugin-api/
function configInit(config) {
if(!config.plugins) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(!config.plugins) {
if (!config.plugins) {

config.plugins = [];
}
config.plugins.push(TopbarPlugin);
}

const TopbarPlugin = (system) => {
return {
// Register an own React component
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Register an own React component
// Register a custom React component

components: {
CustomOperationDetails: class CustomOperationDetails extends system.React.Component {
render() {
const hello = this.props?.operation?.get('x-hello');
if(!hello) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(!hello) {
if (!hello) {

return '';
}
return system.React.createElement('div',
{ className: 'hello' },
hello
);
}
}
},
wrapComponents: {
// wrap the parameters component
parameters: Original => (props => {
// get the custom React component
Comment on lines +1392 to +1394
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// wrap the parameters component
parameters: Original => (props => {
// get the custom React component
// Wrap the parameters component
parameters: Original => (props => {
// Get the custom React component

const CustomOperationDetails = props.getComponent('CustomOperationDetails');
// Use the non JSX React API (https://reactjs.org/docs/react-without-jsx.html)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Use the non JSX React API (https://reactjs.org/docs/react-without-jsx.html)
// Use the non JSX React API (https://react.dev/reference/react/createElement#creating-an-element-without-jsx)

// to create a wrapper div holding our own component and the original parameters component
return system.React.createElement('div',
{ className: "parameters-wrap"},
system.React.createElement(CustomOperationDetails, props),
system.React.createElement(Original, props)
);
Comment on lines +1398 to +1402
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example looks out-of-date compared to the example in the non-obsolete React documentation.

})
}
}
};
```

```csharp
app.UseSwaggerUI(options = >
{
options.InjectJavascript("swagger-ui.js");
});
```


Comment on lines +1410 to +1416
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
app.UseSwaggerUI(options = >
{
options.InjectJavascript("swagger-ui.js");
});
```
app.UseSwaggerUI(options => options.InjectJavascript("swagger-ui.js"));

## Swashbuckle.AspNetCore.Annotations ##

### Install and Enable Annotations ###
Expand Down
5 changes: 5 additions & 0 deletions src/Swashbuckle.AspNetCore.SwaggerUI/index.html
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a sample and/or integration test that can be updated to demonstrate this somehow?

Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@
if (interceptors.ResponseInterceptorFunction)
configObject.responseInterceptor = parseFunction(interceptors.ResponseInterceptorFunction);

// Allow adjusting config through injected JavaScript files
if(typeof initConfig === "function") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(typeof initConfig === "function") {
if (typeof initConfig === "function") {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way of hooking this up as a global that's more robust and/or more likely to not pollute with any existing objects (e.g. what if it was called swashbuckleInitConfig for instance)?

initConfig(configObject, oauthConfigObject);
}

// Begin Swagger UI call region

const ui = SwaggerUIBundle(configObject);
Expand Down