Przeglądaj źródła

Merge pull request #3754 from swagger-api/ft/docs

Expand documentation
bubble
kyle 6 lat temu
committed by GitHub
rodzic
commit
743eb8c9c7
Nie znaleziono w bazie danych klucza dla tego podpisu ID klucza GPG: 4AEE18F83AFDEB23
19 zmienionych plików z 965 dodań i 207 usunięć
  1. +1
    -0
      .gitignore
  2. +17
    -195
      README.md
  3. +12
    -1
      dev-helpers/index.html
  4. +5
    -0
      docs/README.md
  5. +16
    -0
      docs/SUMMARY.md
  6. +3
    -0
      docs/book.json
  7. +92
    -0
      docs/customization/custom-layout.md
  8. +71
    -0
      docs/customization/overview.md
  9. +355
    -0
      docs/customization/plugin-api.md
  10. +24
    -0
      docs/development/setting-up.md
  11. +77
    -0
      docs/usage/configuration.md
  12. +60
    -0
      docs/usage/cors.md
  13. +1
    -1
      docs/usage/deep-linking.md
  14. +93
    -0
      docs/usage/installation.md
  15. +38
    -0
      docs/usage/limitations.md
  16. +28
    -0
      docs/usage/oauth2.md
  17. +3
    -3
      docs/usage/version-detection.md
  18. +15
    -7
      src/core/system.js
  19. +54
    -0
      test/core/system/wrapComponent.js

+ 1
- 0
.gitignore Wyświetl plik

@@ -9,3 +9,4 @@ package-lock.json
*.iml
selenium-debug.log
test/e2e/db.json
docs/_book

+ 17
- 195
README.md Wyświetl plik

@@ -30,32 +30,26 @@ Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13)
1.0.1 | 2011-10-11 | 1.0, 1.1 | [tag v1.0.1](https://github.com/swagger-api/swagger-ui/tree/v1.0.1)

## Documentation

### How to run

##### Easy start! Docker
You can pull a pre-built docker image of the swagger-ui directly from Dockerhub:

```
docker pull swaggerapi/swagger-ui
docker run -p 80:8080 swaggerapi/swagger-ui
```

Will start nginx with swagger-ui on port 80.

Or you can provide your own swagger.json on your host

```
docker run -p 80:8080 -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```
#### Usage
- [Installation](docs/usage/installation.md)
- [Configuration](docs/usage/configuration.md)
- [CORS](docs/usage/cors.md)
- [OAuth2](docs/usage/oauth2.md)
- [Deep Linking](docs/usage/deep-linking.md)
- [Limitations](docs/usage/limitations.md)
- [Version detection](docs/usage/version-detection.md)

The base URL of the web application can be changed by specifying the `BASE_URL` environment variable:
#### Customization
- [Overview](docs/customization/overview.md)
- [Plugin API](docs/customization/plugin-api.md)
- [Custom layout](docs/customization/custom-layout.md)

```
docker run -p 80:8080 -e BASE_URL=/swagger -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```
#### Development
- [Setting up](docs/development/setting-up.md)

This will serve Swagger UI at `/swagger` instead of `/`.
### How to run

##### Prerequisites
- Node 6.x
@@ -76,7 +70,7 @@ http://nightwatchjs.org/gettingstarted#selenium-server-setup
Integration tests can be run locally with `npm run e2e` - be sure you aren't running a dev server when testing!


##### Browser support
### Browser support
Swagger UI works in the latest versions of Chrome, Safari, Firefox, Edge and IE11.

### Known Issues
@@ -89,180 +83,6 @@ To help with the migration, here are the currently known issues with 3.X. This l
- l10n (translations) is not implemented.
- Relative path support for external files is not implemented.

### Direct use of JS and CSS assets
To include the JS, CSS and image assets directly into a webpage, use the [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) package.
The root directory of this package contains the contents of the _dist/_ directory of this repo.
As a node module, `swagger-ui-dist` also exports the `swagger-ui-bundle` and `swagger-ui-standalone-preset` objects.

### SwaggerUIBundle
To use swagger-ui's bundles, you should take a look at the [source of swagger-ui html page](https://github.com/swagger-api/swagger-ui/blob/master/dist/index.html) and customize it. This basically requires you to instantiate a SwaggerUi object as below:

```javascript
const ui = SwaggerUIBundle({
url: "http://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
```

#### OAuth2 configuration
You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle`
default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`,
`useBasicAuthenticationWithAccessCodeGrant`.

Config Name | Description
client_id | Default clientId. MUST be a string
client_secret | Default clientSecret. MUST be a string
realm | realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl` . MUST be a string
appName | application name, displayed in authorization popup. MUST be a string
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encoded[client_id:client_secret]`). The default is `false`

```javascript
const ui = SwaggerUIBundle({...})

// Method can be called in any place after calling constructor SwaggerUIBundle
ui.initOAuth({
clientId: "your-client-id",
clientSecret: "your-client-secret-if-required",
realm: "your-realms",
appName: "your-app-name",
scopeSeparator: " ",
additionalQueryStringParams: {test: "hello"}
})
```

If you'd like to use the bundle files via npm, check out the [`swagger-ui-dist` package](https://www.npmjs.com/package/swagger-ui-dist).

#### Parameters

Parameters with dots in their names are single strings used to organize subordinate parameters, and are not indicative of a nested structure.

Parameter Name | Description
url | The url pointing to API definition (normally `swagger.json` or `swagger.yaml`). Will be ignored if `urls` or `spec` is used.
urls | An array of API definition objects (`{url: "<url>", name: "<name>"}`) used by Topbar plugin. When used and Topbar plugin is enabled, the `url` parameter will not be parsed. Names and URLs must be unique among all items in this array, since they're used as identifiers.
urls.primaryName | When using `urls`, you can use this subparameter. If the value matches the name of a spec provided in `urls`, that spec will be displayed when Swagger-UI loads, instead of defaulting to the first spec in `urls`.
spec | A JSON object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them.
validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation.
dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger.
domNode | The HTML DOM element inside which SwaggerUi will put the user interface for swagger. Overrides `dom_id`.
oauth2RedirectUrl | OAuth redirect URL
tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
defaultModelRendering | Controls how models are shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.) It can be set to 'model' or 'example', and the default is 'example'.
defaultModelExpandDepth | The default expansion depth for models. The default value is 1.
configUrl | Configs URL
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
docExpansion | Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). The default is 'list'.
displayOperationId | Controls the display of operationId in operations list. The default is `false`.
displayRequestDuration | Controls the display of the request duration (in milliseconds) for `Try it out` requests. The default is `false`.
maxDisplayedTags | If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations.
filter | If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be true/false to enable or disable, or an explicit filter string in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag.
deepLinking | If set to `true`, enables dynamic deep linking for tags and operations. [Docs](https://github.com/swagger-api/swagger-ui/blob/master/docs/deep-linking.md)
requestInterceptor | MUST be a function. Function to intercept remote definition, Try-It-Out, and OAuth2 requests. Accepts one argument requestInterceptor(request) and must return the potentially modified request.
responseInterceptor | MUST be a function. Function to intercept remote definition, Try-It-Out, and OAuth2 responses. Accepts one argument responseInterceptor(response) and must return the potentially modified response.
showMutatedRequest | If set to `true` (the default), uses the mutated request returned from a rquestInterceptor to produce the curl command in the UI, otherwise the request before the requestInterceptor was applied is used.
showExtensions | Controls the display of vendor extension (`x-`) fields and values for Operations, Parameters, and Schema. The default is `false`.

### Plugins

#### Topbar plugin
Topbar plugin enables top bar with input for spec path and explore button or a dropdown if `urls` is used. By default the plugin is enabled, and to disable it you need to remove Topbar plugin from presets in `src/standalone/index.js`:

```javascript
let preset = [
// TopbarPlugin,
ConfigsPlugin,
() => {
return {
components: { StandaloneLayout }
}
}
]
```

#### Configs plugin
Configs plugin allows to fetch external configs instead of passing them to `SwaggerUIBundle`. Fetched configs support two formats: JSON or yaml. The plugin is enabled by default.
There are three options of passing config:
- add a query parameter `config` with URL to a server where the configs are hosted. For ex. http://petstore.swagger.io/?config=http://localhost:3001/config.yaml
- add a config `configUrl` with URL to SwaggerUIBundle
- change default configs in `swagger-config.yaml` *Note: after changing, the project must be re-built*

These options can be used altogether, the order of inheritance is following (from the lowest priority to the highest):
`swagger-config.yaml` -> config passed to `SwaggerUIBundle` -> config fetched from `configUrl` passed to `SwaggerUIBundle` -> config fetched from URL passed as a query parameter `config`

## CORS Support

CORS is a technique to prevent websites from doing bad things with your personal data. Most browsers + JavaScript toolkits not only support CORS but enforce it, which has implications for your API server which supports Swagger.

You can read about CORS here: http://www.w3.org/TR/cors.

There are two cases where no action is needed for CORS support:

1. swagger-ui is hosted on the same server as the application itself (same host *and* port).
2. The application is located behind a proxy that enables the required CORS headers. This may already be covered within your organization.

Otherwise, CORS support needs to be enabled for:

1. Your Swagger docs. For Swagger 2.0 it's the `swagger.json`/`swagger.yaml` and any externally `$ref`ed docs.
2. For the `Try it now` button to work, CORS needs to be enabled on your API endpoints as well.

### Testing CORS Support

You can verify CORS support with one of three techniques:

- Curl your API and inspect the headers. For instance:

```bash
$ curl -I "http://petstore.swagger.io/v2/swagger.json"
HTTP/1.1 200 OK
Date: Sat, 31 Jan 2015 23:05:44 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
Content-Type: application/json
Content-Length: 0
```

This tells us that the petstore resource listing supports OPTIONS, and the following headers: `Content-Type`, `api_key`, `Authorization`.

- Try swagger-ui from your file system and look at the debug console. If CORS is not enabled, you'll see something like this:

```
XMLHttpRequest cannot load http://sad.server.com/v2/api-docs. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
```

Swagger-UI cannot easily show this error state.

- Using the http://www.test-cors.org website. Keep in mind this will show a successful result even if `Access-Control-Allow-Headers` is not available, which is still required for Swagger-UI to function properly.

### Enabling CORS

The method of enabling CORS depends on the server and/or framework you use to host your application. http://enable-cors.org provides information on how to enable CORS in some common web servers.

Other servers/frameworks may provide you information on how to enable it specifically in their use case.

### CORS and Header Parameters

Swagger lets you easily send headers as parameters to requests. The name of these headers *MUST* be supported in your CORS configuration as well. From our example above:

```
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
```

Only headers with these names will be allowed to be sent by Swagger-UI.

## Security contact

Please disclose any security-related issues or vulnerabilities by emailing [security@swagger.io](mailto:security@swagger.io), instead of using the public issue tracker.


+ 12
- 1
dev-helpers/index.html Wyświetl plik

@@ -70,6 +70,16 @@
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>

const MyComponentPlugin = function(system) {
return {
components: {
// components can just be functions
// HelloWorld: () => "Hello World"
}
}
}

window.onload = function() {
window["SwaggerUIBundle"] = window["swagger-ui-bundle"]
window["SwaggerUIStandalonePreset"] = window["swagger-ui-standalone-preset"]
@@ -82,7 +92,8 @@
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
SwaggerUIBundle.plugins.DownloadUrl,
MyComponentPlugin
],
layout: "StandaloneLayout"
})


+ 5
- 0
docs/README.md Wyświetl plik

@@ -0,0 +1,5 @@
# Swagger-UI

Welcome to the Swagger-UI documentation!

A table of contents can be found at `SUMMARY.md`.

+ 16
- 0
docs/SUMMARY.md Wyświetl plik

@@ -0,0 +1,16 @@
#### Usage
- [Installation](docs/usage/installation.md)
- [Configuration](docs/usage/configuration.md)
- [CORS](docs/usage/cors.md)
- [OAuth2](docs/usage/oauth2.md)
- [Deep Linking](docs/usage/deep-linking.md)
- [Limitations](docs/usage/limitations.md)
- [Version detection](docs/usage/version-detection.md)

#### Customization
- [Overview](docs/customization/overview.md)
- [Plugin API](docs/customization/plugin-api.md)
- [Custom layout](docs/customization/custom-layout.md)

#### Development
- [Setting up](docs/development/setting-up.md)

+ 3
- 0
docs/book.json Wyświetl plik

@@ -0,0 +1,3 @@
{
"title": "Swagger-UI"
}

+ 92
- 0
docs/customization/custom-layout.md Wyświetl plik

@@ -0,0 +1,92 @@
# Creating a custom layout

**Layouts** are a special type of component that Swagger-UI uses as the root component for the entire application. You can define custom layouts in order to have high-level control over what ends up on the page.

By default, Swagger-UI uses `BaseLayout`, which is built into the application. You can specify a different layout to be used by passing the layout's name as the `layout` parameter to Swagger-UI. Be sure to provide your custom layout as a component to Swagger-UI.

<br>

For example, if you wanted to create a custom layout that only displayed operations, you could define an `OperationsLayout`:

```js
import React from "react"

// Create the layout component
class OperationsLayout extends React.Component {
render() {
const {
getComponent
} = this.props

const Operations = getComponent("Operations", true)

return {
<div>
<Operations />
</div>
}
}
}

// Create the plugin that provides our layout component
const OperationsLayoutPlugin = function() {
return {
components: {
OperationsLayout: OperationsLayout
}
}
}

// Provide the plugin to Swagger-UI, and select OperationsLayout
// as the layout for Swagger-UI
SwaggerUI({
url: "http://petstore.swagger.io/v2/swagger.json",
plugins: [ OperationsLayoutPlugin ],
layout: "OperationsLayout"
})
```

### Augmenting the default layout

If you'd like to build around the `BaseLayout` instead of replacing it, you can pull the `BaseLayout` into your custom layout and use it:

```js
import React from "react"

// Create the layout component
class AugmentingLayout extends React.Component {
render() {
const {
getComponent
} = this.props

const BaseLayout = getComponent("BaseLayout", true)

return {
<div>
<div className="myCustomHeader">
<h1>I have a custom header above Swagger-UI!</h1>
</div>
<BaseLayout />
</div>
}
}
}

// Create the plugin that provides our layout component
const AugmentingLayoutPlugin = function() {
return {
components: {
AugmentingLayout: AugmentingLayout
}
}
}

// Provide the plugin to Swagger-UI, and select AugmentingLayout
// as the layout for Swagger-UI
SwaggerUI({
url: "http://petstore.swagger.io/v2/swagger.json",
plugins: [ AugmentingLayoutPlugin ],
layout: "AugmentingLayout"
})
```

+ 71
- 0
docs/customization/overview.md Wyświetl plik

@@ -0,0 +1,71 @@
# Plugin system overview

### Prior art

Swagger-UI leans heavily on concepts and patterns found in React and Redux.

If you aren't already familiar, here's some suggested reading:

- [React: Quick Start (reactjs.org)](https://reactjs.org/docs/hello-world.html)
- [Redux README (redux.js.org)](http://redux.js.org/)

In the following documentation, we won't take the time to define the fundamentals covered in the resources above.

> **Note**: Some of the examples in this section contain JSX, which is a syntax extension to JavaScript that is useful for writing React components.
>
> If you don't want to set up a build pipeline capable of translating JSX to JavaScript, take a look at [React without JSX (reactjs.org)](https://reactjs.org/docs/react-without-jsx.html). You can use our `system.React` reference to leverage React without needing to pull a copy into your project.

### The System

The _system_ is the heart of the Swagger-UI application. At runtime, it's a JavaScript object that holds many things:

- React components
- Bound Redux actions and reducers
- Bound Reselect state selectors
- System-wide collection of available components
- Built-in helpers like `getComponent`, `makeMappedContainer`, and `getStore`
- References to the React and Immutable.js libraries (`system.React`, `system.Im`)
- User-defined helper functions

The system is built up when Swagger-UI is called by iterating through ("compiling") each plugin that Swagger-UI has been given, through the `presets` and `plugins` configuration options.

### Presets

Presets are arrays of plugins, which are provided to Swagger-UI through the `presets` configuration option. All plugins within presets are compiled before any plugins provided via the `plugins` configuration option. Consider the following example:

```javascript
const MyPreset = [FirstPlugin, SecondPlugin, ThirdPlugin]

SwaggerUI({
presets: [
MyPreset
]
})
```

By default, Swagger-UI includes the internal `ApisPreset`, which contains a set of plugins that provide baseline functionality for Swagger-UI. If you specify your own `presets` option, you need to add the ApisPreset manually, like so:

```javascript
SwaggerUI({
presets: [
SwaggerUI.presets.apis,
MyAmazingCustomPreset
]
})
```

The need to provide the `apis` preset when adding other presets is an artifact of Swagger-UI's original design, and will likely be removed in the next major version.

### getComponent

`getComponent` is a helper function injected into every container component, which is used to get references to components provided by the plugin system.

All components should be loaded through `getComponent`, since it allows other plugins to modify the component. It is preferred over a conventional `import` statement.

Container components in Swagger-UI can be loaded by passing `true` as the second argument to `getComponent`, like so:

```javascript
getComponent("ContainerComponentName", true)
```

This will map the current system as props to the component.

+ 355
- 0
docs/customization/plugin-api.md Wyświetl plik

@@ -0,0 +1,355 @@
# Plugins

A plugin is a function that returns an object - more specifically, the object may contain functions and components that augment and modify Swagger-UI's functionality.

### Format

A plugin return value may contain any of these keys, where `myStateKey` is a name for a piece of state:

```javascript
{
statePlugins: {
myStateKey: {
actions,
reducers,
selectors,
wrapActions,
wrapSelectors
}
},
components: {},
wrapComponents: {},
fn: {}
}
```

### System is provided to plugins

Let's assume we have a plugin, `NormalPlugin`, that exposes a `doStuff` action under the `normal` state namespace.

```javascript
const ExtendingPlugin = function(system) {
return {
statePlugins: {
extending: {
actions: {
doExtendedThings: function(...args) {
// you can do other things in here if you want
return system.normalActions.doStuff(...args)
}
}
}
}
}
}
```

As you can see, each plugin is passed a reference to the `system` being built up. As long as `NormalPlugin` is compiled before `ExtendingPlugin`, this will work without any issues.

There is no dependency management built into the plugin system, so if you create a plugin that relies on another, it is your responsibility to make sure that the dependent plugin is loaded _after_ the plugin being depended on.

### Interfaces

##### Actions

```javascript
const MyActionPlugin = () => {
return {
statePlugins: {
example: {
actions: {
updateFavoriteColor: (str) => {
return {
type: "EXAMPLE_SET_FAV_COLOR",
payload: str
}
}
}
}
}
}
}
```

Once an action has been defined, you can use it anywhere that you can get a system reference:

```javascript
// elsewhere
system.exampleActions.updateFavoriteColor("blue")
```

The Action interface enables the creation of new Redux action creators within a piece of state in the Swagger-UI system.

This action creator function will be exposed to container components as `exampleActions.updateFavoriteColor`. When this action creator is called, the return value (which should be a [Flux Standard Action](https://github.com/acdlite/flux-standard-action)) will be passed to the `example` reducer, which we'll define in the next section.

For more information about the concept of actions in Redux, see the [Redux Actions documentation](http://redux.js.org/docs/basics/Actions.html).

##### Reducers

Reducers take a state (which is an [Immutable.js map](https://facebook.github.io/immutable-js/docs/#/Map)) and an action, and return a new state.

Reducers must be provided to the system under the name of the action type that they handle, in this case, `EXAMPLE_SET_FAV_COLOR`.

```javascript
const MyReducerPlugin = function(system) {
return {
statePlugins: {
example: {
reducers: {
"EXAMPLE_SET_FAV_COLOR": (state, action) => {
// you're only working with the state under the namespace, in this case "example".
// So you can do what you want, without worrying about /other/ namespaces
return state.set("favColor", action.payload)
}
}
}
}
}
}
```

##### Selectors

Selectors reach into

They're an easy way to keep logic for getting data out of state in one place, and is preferred over passing state data directly into components.


```javascript
const MySelectorPlugin = function(system) {
return {
statePlugins: {
example: {
selectors: {
myFavoriteColor: (state) => state.get("favColor")
}
}
}
}
}
```

You can also use the Reselect library to memoize your selectors, which is recommended for any selectors that will see heavy use, since Reselect automatically memoizes selector calls for you:

```javascript
import { createSelector } from "reselect"

const MySelectorPlugin = function(system) {
return {
statePlugins: {
example: {
selectors: {
// this selector will be memoized after it is run once for a
// value of `state`
myFavoriteColor: createSelector((state) => state.get("favColor"))
}
}
}
}
}
```

Once a selector has been defined, you can use it anywhere that you can get a system reference:
```javascript
system.exampleSelectors.myFavoriteColor() // gets `favColor` in state for you
```

##### Components

You can provide a map of components to be integrated into the system.

Be mindful of the key names for the components you provide, as you'll need to use those names to refer to the components elsewhere.

```javascript
class HelloWorldClass extends React.Component {
render() {
return <h1>Hello World!</h1>
}
}

const MyComponentPlugin = function(system) {
return {
components: {
HelloWorldClass: HelloWorldClass
// components can just be functions, these are called "stateless components"
HelloWorldStateless: () => <h1>Hello World!</h1>,
}
}
}
```

```javascript
// elsewhere
const HelloWorldStateless = system.getComponent("HelloWorldStateless")
const HelloWorldClass = system.getComponent("HelloWorldClass")
```

You can also "cancel out" any components that you don't want by creating a stateless component that always returns `null`:

```javascript
const NeverShowInfoPlugin = function(system) {
return {
components: {
info: () => null
}
}
}
```

##### Wrap-Actions

Wrap Actions allow you to override the behavior of an action in the system.

They are function factories with the signature `(oriAction, system) => (...args) => result`.

A Wrap Action's first argument is `oriAction`, which is the action being wrapped. It is your responsibility to call the `oriAction` - if you don't, the original action will not fire!

This mechanism is useful for conditionally overriding built-in behaviors, or listening to actions.

```javascript
// FYI: in an actual Swagger-UI, `updateSpec` is already defined in the core code
// it's just here for clarity on what's behind the scenes
const MySpecPlugin = function(system) {
return {
statePlugins: {
spec: {
actions: {
updateSpec: (str) => {
return {
type: "SPEC_UPDATE_SPEC",
payload: str
}
}
}
}
}
}
}

// this plugin allows you to watch changes to the spec that is in memory
const MyWrapActionPlugin = function(system) {
return {
statePlugins: {
spec: {
wrapActions: {
updateSpec: (oriAction, system) => (str) => {
// here, you can hand the value to some function that exists outside of Swagger-UI
console.log("Here is my API definition", str)
return oriAction(str) // don't forget! otherwise, Swagger-UI won't update
}
}
}
}
}
}
```

##### Wrap-Selectors

Wrap Selectors allow you to override the behavior of a selector in the system.

They are function factories with the signature `(oriSelector, system) => (state, ...args) => result`.

This interface is useful for controlling what data flows into components. We use this in the core code to disable selectors based on the API definition's version.

```javascript
import { createSelector } from 'reselect'

// FYI: in an actual Swagger-UI, the `url` spec selector is already defined
// it's just here for clarity on what's behind the scenes
const MySpecPlugin = function(system) {
return {
statePlugins: {
spec: {
selectors: {
url: createSelector(
state => state.get("url")
)
}
}
}
}
}

const MyWrapSelectorsPlugin = function(system) {
return {
statePlugins: {
spec: {
wrapSelectors: {
url: (oriSelector, system) => (state, ...args) => {
console.log('someone asked for the spec url!!! it is', state.get('url'))
// you can return other values here...
// but let's just enable the default behavior
return oriSelector(state, ...args)
}
}
}
}
}
}
```

##### Wrap-Components

Wrap Components allow you to override a component registered within the system.

Wrap Components are function factories with the signature `(OriginalComponent, system) => props => ReactElement`.

```javascript
const MyWrapBuiltinComponentPlugin = function(system) {
return {
wrapComponents: {
info: (Original, system) => (props) => {
return <div>
<h3>Hello world! I am above the Info component.</h3>
<Original {...props} />
</div>
}
}
}
}
```

```javascript
// Overriding a component from a plugin

const MyNumberDisplayPlugin = function(system) {
return {
components: {
NumberDisplay: ({ number }) => <span>{number}</span>
}
}
}

const MyWrapComponentPlugin = function(system) {
return {
wrapComponents: {
NumberDisplay: (Original, system) => (props) => {
if(props.number > 10) {
return <div>
<h3>Warning! Big number ahead.</h3>
</div>
} else {
return <Original {...props} />
}
}
}
}
}
```

##### fn

The fn interface allows you to add helper functions to the system for use elsewhere.

```javascript
import leftPad from "left-pad"

const MyFnPlugin = function(system) {
return {
fn: {
leftPad: leftPad
}
}
}
```

+ 24
- 0
docs/development/setting-up.md Wyświetl plik

@@ -0,0 +1,24 @@
# Setting up a dev environment

Swagger-UI includes a development server that provides hot module reloading and unminified stack traces, for easier development.

### Prerequisites

- Node.js `6.0.0` or greater
- npm `3.0.0` or greater
- git, any version


### Steps

1. `git clone git@github.com:swagger-api/swagger-ui.git`
2. `cd swagger-ui`
3. `npm install`
4. `npm run dev`
5. Wait a bit
6. Open http://localhost:3200/

## Bonus points

- Swagger-UI includes an ESLint rule definition. If you use a graphical editor, consider installing an ESLint plugin, which will point out syntax and style errors for you as you code.
- The linter runs as part of the PR test sequence, so don't think you can get away with not paying attention to it!

+ 77
- 0
docs/usage/configuration.md Wyświetl plik

@@ -0,0 +1,77 @@
# Configuration

### How to configure

Swagger-UI accepts configuration parameters in four locations.

From lowest to highest precedence:
- The `swagger-config.yaml` in the project root directory, if it exists, is baked into the application
- configuration object passed as an argument to Swagger-UI (`SwaggerUI({ ... })`)
- configuration document fetched from a specified `configUrl`
- configuration items passed as key/value pairs in the URL query string


### Parameters

Parameters with dots in their names are single strings used to organize subordinate parameters, and are not indicative of a nested structure.

For readability, parameters are grouped by category and sorted alphabetically.

Type notations are formatted like so:
- `String=""` means a String type with a default value of `""`.
- `String=["a"*, "b", "c", "d"]` means a String type that can be `a`, `b`, `c`, or `d`, with the `*` indicating that `a` is the default value.

##### Core

Parameter Name | Description
--- | ---
`configUrl` | `String`. URL to fetch external configuration document from.
`dom_id` |`String`, **REQUIRED** if `domNode` is not provided. The id of a dom element inside which SwaggerUi will put the user interface for swagger.
`domNode` | `Element`, **REQUIRED** if `dom_id` is not provided. The HTML DOM element inside which SwaggerUi will put the user interface for swagger. Overrides `dom_id`.
`spec` | `Object={}`. A JS object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them.
`url` | `String`. The url pointing to API definition (normally `swagger.json` or `swagger.yaml`). Will be ignored if `urls` or `spec` is used.
`urls` | `String`. An array of API definition objects (`{url: "<url>", name: "<name>"}`) used by Topbar plugin. When used and Topbar plugin is enabled, the `url` parameter will not be parsed. Names and URLs must be unique among all items in this array, since they're used as identifiers.
`urls.primaryName` | `String`. When using `urls`, you can use this subparameter. If the value matches the name of a spec provided in `urls`, that spec will be displayed when Swagger-UI loads, instead of defaulting to the first spec in `urls`.

##### Plugin system

Read more about the plugin system in the [Customization documentation](/docs/customization/overview.md).

Parameter Name | Description
--- | ---
`layout` | `String="BaseLayout"`. The name of a component available via the plugin system to use as the top-level layout for Swagger-UI.
`plugins` | `Array=[]`. An array of plugin functions to use in Swagger-UI.
`presets` | `Array=[SwaggerUI.presets.ApisPreset]`. An array of presets to use in Swagger-UI. Usually, you'll want to include `ApisPreset` if you use this option.

##### Display

Parameter Name | Description
--- | ---
`deepLinking` | `Boolean=false`. If set to `true`, enables deep linking for tags and operations. See the [Deep Linking documentation](https://github.com/swagger-api/swagger-ui/blob/master/docs/deep-linking.md) for more information.
`displayOperationId` | `Boolean=false`. Controls the display of operationId in operations list. The default is `false`.
`defaultModelExpandDepth` | `Number=1`. The default expansion depth for models.
`defaultModelRendering` | `String=["example"*, "model"]`. Controls how models are shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.)
`displayRequestDuration` | `Boolean=false`. Controls the display of the request duration (in milliseconds) for Try-It-Out requests.
`docExpansion` | `String=["list"*, "full", "none"]`. Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing).
`filter` | `Boolean=false OR String`. If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be Boolean to enable or disable, or a string, in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag.
`maxDisplayedTags` | `Number`. If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations.
`operationsSorter` | `Function=(a => a)`. Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
`showExtensions` | `Boolean=false`. Controls the display of vendor extension (`x-`) fields and values for Operations, Parameters, and Schema.
`tagsSorter` | `Function=(a => a)`. Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.

##### Network

Parameter Name | Description
--- | ---
`oauth2RedirectUrl` | `String`. OAuth redirect URL.
`requestInterceptor` | `Function=(a => a)`. MUST be a function. Function to intercept remote definition, Try-It-Out, and OAuth2 requests. Accepts one argument requestInterceptor(request) and must return the potentially modified request.
`responseInterceptor` |`Function=(a => a)`. MUST be a function. Function to intercept remote definition, Try-It-Out, and OAuth2 responses. Accepts one argument responseInterceptor(response) and must return the potentially modified response.
`showMutatedRequest` | `Boolean=true`. If set to `true`, uses the mutated request returned from a requestInterceptor to produce the curl command in the UI, otherwise the request before the requestInterceptor was applied is used.
`validatorUrl` | `String="https://online.swagger.io/validator" OR null`. By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation.

##### Macros

Parameter Name | Description
--- | ---
`modelPropertyMacro` | `Function`. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
`parameterMacro` | `Function`. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable

+ 60
- 0
docs/usage/cors.md Wyświetl plik

@@ -0,0 +1,60 @@
# CORS

CORS is a technique to prevent websites from doing bad things with your personal data. Most browsers + JavaScript toolkits not only support CORS but enforce it, which has implications for your API server which supports Swagger.

You can read about CORS here: http://www.w3.org/TR/cors.

There are two cases where no action is needed for CORS support:

1. swagger-ui is hosted on the same server as the application itself (same host *and* port).
2. The application is located behind a proxy that enables the required CORS headers. This may already be covered within your organization.

Otherwise, CORS support needs to be enabled for:

1. Your Swagger docs. For Swagger 2.0 it's the `swagger.json`/`swagger.yaml` and any externally `$ref`ed docs.
2. For the `Try it now` button to work, CORS needs to be enabled on your API endpoints as well.

### Testing CORS Support

You can verify CORS support with one of three techniques:

- Curl your API and inspect the headers. For instance:

```bash
$ curl -I "http://petstore.swagger.io/v2/swagger.json"
HTTP/1.1 200 OK
Date: Sat, 31 Jan 2015 23:05:44 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
Content-Type: application/json
Content-Length: 0
```

This tells us that the petstore resource listing supports OPTIONS, and the following headers: `Content-Type`, `api_key`, `Authorization`.

- Try swagger-ui from your file system and look at the debug console. If CORS is not enabled, you'll see something like this:

```
XMLHttpRequest cannot load http://sad.server.com/v2/api-docs. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
```

Swagger-UI cannot easily show this error state.

- Using the http://www.test-cors.org website. Keep in mind this will show a successful result even if `Access-Control-Allow-Headers` is not available, which is still required for Swagger-UI to function properly.

### Enabling CORS

The method of enabling CORS depends on the server and/or framework you use to host your application. http://enable-cors.org provides information on how to enable CORS in some common web servers.

Other servers/frameworks may provide you information on how to enable it specifically in their use case.

### CORS and Header Parameters

Swagger lets you easily send headers as parameters to requests. The name of these headers *MUST* be supported in your CORS configuration as well. From our example above:

```
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
```

Only headers with these names will be allowed to be sent by Swagger-UI.

docs/deep-linking.md → docs/usage/deep-linking.md Wyświetl plik

@@ -1,4 +1,4 @@
# Deep linking
# `deepLinking` parameter

Swagger-UI allows you to deeply link into tags and operations within a spec. When Swagger-UI is provided a URL fragment at runtime, it will automatically expand and scroll to a specified tag or operation.


+ 93
- 0
docs/usage/installation.md Wyświetl plik

@@ -0,0 +1,93 @@
# Installation

## Distribution channels

### NPM Registry

We publish two modules to npm: **`swagger-ui`** and **`swagger-ui-dist`**.

**`swagger-ui`** is meant for consumption by JavaScript web projects that include module bundlers, such as Webpack, Browserify, and Rollup. Its main file exports Swagger-UI's main function, and the module also includes a namespaced stylesheet at `swagger-ui/dist/swagger-ui.css`. Here's an example:

```javascript
import SwaggerUI from 'swagger-ui'
// or use require, if you prefer
const SwaggerUI = require('swagger-ui')

SwaggerUI({
dom_id: '#myDomId'
})
```

In contrast, **`swagger-ui-dist`** is meant for server-side projects that need assets to serve to clients. The module, when imported, includes an `absolutePath` helper function that returns the absolute filesystem path to where the `swagger-ui-dist` module is installed.

_Note: we suggest using `swagger-ui` when your tooling makes it possible, as `swagger-ui-dist`
will result in more code going across the wire._

The module's contents mirrors the `dist` folder you see in the Git repository. The most useful file is `swagger-ui-bundle.js`, which is a build of Swagger-UI that includes all the code it needs to run in one file. The folder also has an `index.html` asset, to make it easy to serve Swagger-UI like so:

```javascript
const express = require('express')
const pathToSwaggerUi = require('swagger-ui').absolutePath()

const app = express()

app.use(express.static(pathToSwaggerUi))

app.listen(3000)
```

The module also exports `SwaggerUIBundle` and `SwaggerUIStandalonePreset`, so
if you're in a JavaScript project that can't handle a tranditional npm module,
you could do something like this:

```js
var SwaggerUIBundle = require('swagger-ui-dist').SwaggerUIBundle

const ui = SwaggerUIBundle({
url: "http://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
]
layout: "StandaloneLayout"
})
```

`SwaggerUIBundle` is equivalent to `SwaggerUI`.

### Docker Hub

You can pull a pre-built docker image of the swagger-ui directly from Dockerhub:

```
docker pull swaggerapi/swagger-ui
docker run -p 80:8080 swaggerapi/swagger-ui
```

Will start nginx with swagger-ui on port 80.

Or you can provide your own swagger.json on your host

```
docker run -p 80:8080 -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```

The base URL of the web application can be changed by specifying the `BASE_URL` environment variable:

```
docker run -p 80:8080 -e BASE_URL=/swagger -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```

This will serve Swagger UI at `/swagger` instead of `/`.

### unpkg

You can embed Swagger-UI's code directly in your HTML by using unkpg's interface:

```html
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js">
<!-- `SwaggerUIBundle` is now available on the page -->
```

See [unpkg's main page](https://unpkg.com/) for more information on how to use unpkg.

+ 38
- 0
docs/usage/limitations.md Wyświetl plik

@@ -0,0 +1,38 @@
# Limitations

### Forbidden header names

Some header names cannot be controlled by web applications, due to security
features built into web browsers.

Forbidden headers include:

> - Accept-Charset
> - Accept-Encoding
> - Access-Control-Request-Headers
> - Access-Control-Request-Method
> - Connection
> - Content-Length
> - Cookie
> - Cookie2
> - Date
> - DNT
> - Expect
> - Host
> - Keep-Alive
> - Origin
> - Proxy-*
> - Sec-*
> - Referer
> - TE
> - Trailer
> - Transfer-Encoding
> - Upgrade
> - Via
>
> _[Forbidden header names (developer.mozilla.org)](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name)_

The biggest impact of this is that OpenAPI 3.0 Cookie parameters cannot be
controlled when running Swagger-UI in a browser.

For more context, see [#3956](https://github.com/swagger-api/swagger-ui/issues/3956).

+ 28
- 0
docs/usage/oauth2.md Wyświetl plik

@@ -0,0 +1,28 @@
# OAuth2 configuration
You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle`
default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`,
`useBasicAuthenticationWithAccessCodeGrant`.

Config Name | Description
--- | ---
client_id | Default clientId. MUST be a string
client_secret | Default clientSecret. MUST be a string
realm | realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl` . MUST be a string
appName | application name, displayed in authorization popup. MUST be a string
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encoded[client_id:client_secret]`). The default is `false`

```javascript
const ui = SwaggerUI({...})

// Method can be called in any place after calling constructor SwaggerUIBundle
ui.initOAuth({
clientId: "your-client-id",
clientSecret: "your-client-secret-if-required",
realm: "your-realms",
appName: "your-app-name",
scopeSeparator: " ",
additionalQueryStringParams: {test: "hello"}
})
```

docs/version-detection.md → docs/usage/version-detection.md Wyświetl plik

@@ -1,6 +1,6 @@
# Detecting your Swagger-UI version

At times, you're going to need to know which version of Swagger-UI you use.
At times, you're going to need to know which version of Swagger-UI you use.

The first step would be to detect which major version you currently use, as the method of detecting the version has changed. If your Swagger-UI has been heavily modified and you cannot detect from the look and feel which major version you use, you'd have to try both methods to get the exact version.

@@ -9,7 +9,7 @@ To help you visually detect which version you're using, we've included supportin

# Swagger-UI 3.X

![Swagger-UI 3](images/swagger-ui3.png)
![Swagger-UI 3](/docs/images/swagger-ui3.png)

Some distinct identifiers to Swagger-UI 3.X:
- The API version appears as a badge next to its title.
@@ -29,7 +29,7 @@ Note: This functionality was added in 3.0.8. If you're unable to execute it, you

# Swagger-UI 2.X and under

![Swagger-UI 2](images/swagger-ui2.png)
![Swagger-UI 2](/docs/images/swagger-ui2.png)

Some distinct identifiers to Swagger-UI 3.X:
- The API version appears at the bottom of the page.

+ 15
- 7
src/core/system.js Wyświetl plik

@@ -1,3 +1,4 @@
import React from "react"
import { createStore, applyMiddleware, bindActionCreators, compose } from "redux"
import Im, { fromJS, Map } from "immutable"
import deepExtend from "deep-extend"
@@ -97,7 +98,8 @@ export default class Store {
getComponents: this.getComponents.bind(this),
getState: this.getStore().getState,
getConfigs: this._getConfigs.bind(this),
Im
Im,
React
}, this.system.rootInjects || {})
}

@@ -264,8 +266,9 @@ export default class Store {

dispatch = dispatch || this.getStore().dispatch

const process = creator =>{
const actions = this.getActions()

const process = creator =>{
if( typeof( creator ) !== "function" ) {
return objMap(creator, prop => process(prop))
}
@@ -284,7 +287,7 @@ export default class Store {
}

}
return objMap(this.getActions(), actionCreator => bindActionCreators( process( actionCreator ), dispatch ) )
return objMap(actions, actionCreator => bindActionCreators( process( actionCreator ), dispatch ) )
}

getMapStateToProps() {
@@ -333,17 +336,22 @@ function systemExtend(dest={}, src={}) {
// Parses existing components in the system, and prepares them for wrapping via getComponents
if(src.wrapComponents) {
objMap(src.wrapComponents, (wrapperFn, key) => {
const ori = dest.components[key]
const ori = dest.components && dest.components[key]
if(ori && Array.isArray(ori)) {
dest.components[key] = ori.concat([wrapperFn])
delete src.wrapComponents[key]
} else if(ori) {
dest.components[key] = [ori, wrapperFn]
} else {
dest.components[key] = null
delete src.wrapComponents[key]
}
})

delete src.wrapComponents
if(!Object.keys(src.wrapComponents).length) {
// only delete wrapComponents if we've matched all of our wrappers to components
// this handles cases where the component to wrap may be out of our scope,
// but a higher recursive `combinePlugins` call will be able to handle it.
delete src.wrapComponents
}
}




+ 54
- 0
test/core/system/wrapComponent.js Wyświetl plik

@@ -136,4 +136,58 @@ describe("wrapComponents", () => {
expect(children.eq(0).text()).toEqual("Original component")
expect(children.eq(1).text()).toEqual("WOW much data")
})

it("should wrap correctly when registering more plugins", function(){

// Given

const mySystem = new System({
plugins: [
() => {
return {
statePlugins: {
doge: {
selectors: {
wow: () => () => {
return "WOW much data"
}
}
}
},
components: {
wow: () => <div>Original component</div>
}
}
}
]
})

mySystem.register([
function() {
return {
// Wrap the component and use the system
wrapComponents: {
wow: (OriginalComponent, system) => (props) => {
return <container>
<OriginalComponent {...props}></OriginalComponent>
<div>{system.dogeSelectors.wow()}</div>
</container>
}
}
}
}
])

// Then
var Component = mySystem.getSystem().getComponents("wow")
const wrapper = render(<Component name="Normal" />)

const container = wrapper.children().first()
expect(container[0].name).toEqual("container")

const children = container.children()
expect(children.length).toEqual(2)
expect(children.eq(0).text()).toEqual("Original component")
expect(children.eq(1).text()).toEqual("WOW much data")
})
})

Ładowanie…
Anuluj
Zapisz