swagger-ui icon indicating copy to clipboard operation
swagger-ui copied to clipboard

Detecting default server url

Open domenkozar opened this issue 7 years ago • 11 comments

Is your feature request related to a problem?

We have different server urls: localhost, review apps, staging and production. Everytime one uses swagger ui, they have to pick correct server first. Currently default server url is the first configured, this can be confusing since swagger is sending request somewhere else, getting one to think something is wrong with the current url.

Describe the solution you'd like

It would be intuitive if server url was picked to match the browser url from where swagger ui is served (if it does match).

domenkozar avatar Jul 20 '18 10:07 domenkozar

What about maintaining a list of links to different environments, e.g.

  • Production: http://petstore.swagger.io/?url=http://www.example.com/swagger-api-docs.yaml
  • Staging: http://petstore.swagger.io/?url=http://staging.example.com/swagger-api-docs.yaml
  • Dev: http://petstore.swagger.io/?url=http://dev.example.com/swagger-api-docs.yaml

bestmike007 avatar Jul 20 '18 10:07 bestmike007

It's hard to implement that, since review apps post different url for each PR, changing heroku github bot to append the correct url is probably not possible - I doubt it allows configuration.

What's prevent swagger ui to do the right thing? The algorithm would be:

  1. go over list of servers, top to bottom
  2. for each item, check if it matches prefix of browser url
  3. if they match, pick as default and stop
  4. if none of the urls in list matches, pick the first server as default

domenkozar avatar Jul 20 '18 10:07 domenkozar

Are you using a shared instance like http://swagger-ui.your-project.com? If you do so, you can customize it.

If I'm getting this right, you can write your own logic to place these lines: https://github.com/swagger-api/swagger-ui/blob/v3.17.4/dist/index.html#L42-L54.

bestmike007 avatar Jul 20 '18 10:07 bestmike007

I'm not following what configuration exactly should change this. I have:

const ui = SwaggerUIBundle({
  url: "https://custom-app-pr-61.herokuapp.com/api/v1/openapi.yaml",
  dom_id: '#swagger-ui',
  deepLinking: true,
  presets: [
   SwaggerUIBundle.presets.apis,
   SwaggerUIStandalonePreset
  ],
  plugins: [
   SwaggerUIBundle.plugins.DownloadUrl
  ],
  layout: "StandaloneLayout"
})

But regardless of url, it still picks http://localhost as default.

domenkozar avatar Jul 20 '18 10:07 domenkozar

So you have multiple servers for several environment in the same api document?

In such case, yes, the first server will be selected by default: https://github.com/swagger-api/swagger-ui/blob/v3.17.4/src/core/plugins/oas3/components/servers.jsx#L25

You could write a wrapComponent plugin to override this behavior. Refs:

  • https://github.com/swagger-api/swagger-ui/blob/v3.17.4/docs/customization/plugin-api.md#wrap-components
  • https://github.com/swagger-api/swagger-ui/blob/v3.17.4/docs/usage/configuration.md#plugin-system

Or alternatively, wrap the selector: https://github.com/swagger-api/swagger-ui/blob/v3.17.4/src/core/plugins/oas3/selectors.js#L20

bestmike007 avatar Jul 20 '18 15:07 bestmike007

Couldn't wrap my head around this wrapping business, so I have a rather dirty hack in place to preselect a certain server from the list by programmatically triggering the select box.

Would appreciate a option to pre-select a server via maybe by the URL or a user-defined function that receives the servers array and returns a index to select.

silverwind avatar Aug 23 '18 15:08 silverwind

I know this is an old issue but I ran into a similar one where I have a list of servers and want to make sure the appropriate one is only showing up in each environment. This is my list of servers in the swagger.json.

"servers": [
    {
      "url": "http://localhost:3000",
      "description": "Local server",
      "env": "LOCAL"
    },
    {
      "url": "https://my-dev.fmr.com",
      "description": "DEV Environment",
      "env": "DEV"
    },
    {
      "url": "https://my-qa.fmr.com",
      "description": "QA Environment",
      "env": "QA"
    },
    {
      "url": "https://my-preprod.fmr.com",
      "description": "PREPROD Environment",
      "env": "PREPROD"
    }
  ]

in the index.html page, I added the follwing function:

const detectEnvironment = () => {
  const host = window.location.host.toLowerCase();
  if (host.indexOf("localhost") > -1) {
    return "LOCAL";
  } else if (host.indexOf("dev") > -1) {
    return "DEV";
  } else if (host.toLowerCase().indexOf("qa") > -1) {
    return "QA";
  } else if (host.toLowerCase().indexOf("preprod") > -1) {
    return "PREPROD";
  }
};

and I finally added the following code in the onComplete portion of the SwaggerUiBundle.

const ui = SwaggerUIBundle({
  url: "./swagger.json",
  dom_id: "#swagger-ui",
  deepLinking: true,
  presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
  plugins: [SwaggerUIBundle.plugins.DownloadUrl],
  layout: "StandaloneLayout",
  onComplete: function () {
    const env = detectEnvironment();
    let spec = ui.specSelectors.specJson().toJS();
    let servers = spec.servers.filter((item) => {
      return item.env.toLowerCase() === env.toLowerCase();
    });
    spec.servers = servers;
    ui.specActions.updateJsonSpec(spec);
  },
});

I know it is probably crude but it does the trick.

ultrarunner avatar Mar 11 '21 04:03 ultrarunner

You could make Swagger's default "/" server URL work for you if you explicitly add it as the first server in the list. Here's what my servers' list looks like - does the trick, and not even ugly, in my opinion, even somewhat intuitive :) servers: - url: "/" description: "This realm"

  • url: "http://my.dev.host:3000" description: "Dev"
  • url: "http://my.qa.host:3000" description: "QA"
  • url: "http://my.prod.host:3000" description: "PROD"

detkin82 avatar Feb 15 '22 21:02 detkin82

in my case I am using FastApi, and I have an openapi.json that has more than one server (different hosts) and each path correctly specifies its own correct server.

However as mentioned above the UI gives me as default server for all the paths the first server in the servers list.

Really a shame, as openapi.json contemplates this case and allows correctly to define different servers for different paths.

marianobilli avatar Oct 17 '24 16:10 marianobilli

@detkin82 solved the problem by adding a 'This realm' server at '/'. When the API is mounted at different end-points, for example https://prod.example.org/services/apis/myapi or https://dev.example.org/myapi, the '/' trick does not work.

For me, it worked to use a path relative to the api-docs path (the path where the swagger-ui is mounted)

servers:
  - url: ../
    description: This realm
  - url: http://localhost:3000
    description: Development server
  - url: https://example.org/myapi
    description: Public server

anneb avatar Nov 11 '24 11:11 anneb

I had the same issue with multiple Server Urls and I've juste made my own wrapper to select the good one :

window.onload = function() {
	const AutoSelectServerPlugin = function() {
		return {
			statePlugins: {
				spec: {
					wrapSelectors: {
						servers: (oriSelector) => (state, ...args) => {
							const servers = oriSelector(state, ...args);
							if (!servers || servers.size === 0) return servers;
							
							// chercher le serveur voulu dans la List Immutable
							const matchedIndex = servers.findIndex(s => s.get('url') === window.location.origin);
							if (matchedIndex >= 0) {
								// déplacer le serveur voulu en premier
								const matched = servers.get(matchedIndex);
								const rest = servers.delete(matchedIndex);
								return rest.unshift(matched); // retourne une nouvelle List Immutable
							}
							
							return servers;
						}
					}
				}
			}
		};
	};

	window.ui = SwaggerUIBundle({
		url: "/openapi.json",
		dom_id: '#swagger-ui',
		deepLinking: true,
		presets: [
			SwaggerUIBundle.presets.apis,
			SwaggerUIStandalonePreset
		],
		plugins: [
			SwaggerUIBundle.plugins.DownloadUrl,
			AutoSelectServerPlugin
		],
	});
};

trenyture avatar Sep 15 '25 11:09 trenyture