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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ target
*.iws
/dep
out
.DS_Store
.DS_Store
.vscode
4 changes: 2 additions & 2 deletions dropwizard-swagger-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parent>
<groupId>in.vectorpro.dropwizard</groupId>
<artifactId>dropwizard-swagger-parent</artifactId>
<version>2.1.12-2</version>
<version>2.1.12-3</version>
</parent>

<artifactId>dropwizard-swagger-bom</artifactId>
Expand Down Expand Up @@ -73,7 +73,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dependency>
<groupId>in.vectorpro.dropwizard</groupId>
<artifactId>dropwizard-swagger</artifactId>
<version>2.1.12-2</version>
<version>2.1.12-3</version>
</dependency>
<dependency>
<groupId>in.vectorpro.dropwizard</groupId>
Expand Down
2 changes: 1 addition & 1 deletion dropwizard-swagger/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>in.vectorpro.dropwizard</groupId>
<artifactId>dropwizard-swagger-parent</artifactId>
<version>2.1.12-2</version>
<version>2.1.12-3</version>
</parent>

<artifactId>dropwizard-swagger</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ public void initialize(Bootstrap<?> bootstrap) {

@Override
public void run(T configuration, Environment environment) throws Exception {

final SwaggerBundleConfiguration swaggerBundleConfiguration =
getSwaggerBundleConfiguration(configuration);

if (swaggerBundleConfiguration == null) {
throw new IllegalStateException(
"You need to provide an instance of SwaggerBundleConfiguration");
Expand All @@ -55,6 +57,7 @@ public void run(T configuration, Environment environment) throws Exception {

final ConfigurationHelper configurationHelper =
new ConfigurationHelper(configuration, swaggerBundleConfiguration);

new AssetsBundle(
"/swagger-static", configurationHelper.getSwaggerUriPath(), null, "swagger-assets")
.run(configuration, environment);
Expand All @@ -67,20 +70,19 @@ public void run(T configuration, Environment environment) throws Exception {
.run(configuration, environment);

final SwaggerConfiguration oasConfiguration = swaggerBundleConfiguration.build();
new JaxrsOpenApiContextBuilder().openApiConfiguration(oasConfiguration).buildContext(true);
new JaxrsOpenApiContextBuilder<>().openApiConfiguration(oasConfiguration).buildContext(true);

environment.jersey().register(new OpenApiResource());
environment.jersey().register(new BackwardsCompatibleSwaggerResource());
environment.jersey().register(new SwaggerSerializers());

if (swaggerBundleConfiguration.isIncludeSwaggerResource()) {
environment
.jersey()
.register(
new SwaggerResource(
configurationHelper.getUrlPattern(),
swaggerBundleConfiguration.getSwaggerViewConfiguration(),
swaggerBundleConfiguration.getSwaggerOAuth2Configuration(),
swaggerBundleConfiguration.getContextRoot()));
swaggerBundleConfiguration.getSwaggerOAuth2Configuration()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,21 @@
@Path(PATH)
@Produces(MediaType.TEXT_HTML)
public class SwaggerResource {

static final String PATH = "/swagger";

private final SwaggerViewConfiguration viewConfiguration;
private final SwaggerOAuth2Configuration oAuth2Configuration;
private final String contextRoot;
private final String urlPattern;

public SwaggerResource(
String urlPattern,
SwaggerViewConfiguration viewConfiguration,
SwaggerOAuth2Configuration oAuth2Configuration) {
this.urlPattern = urlPattern;
this.viewConfiguration = viewConfiguration;
this.oAuth2Configuration = oAuth2Configuration;
this.contextRoot = "/";
}

public SwaggerResource(
String urlPattern,
SwaggerViewConfiguration viewConfiguration,
SwaggerOAuth2Configuration oAuth2Configuration,
String contextRoot) {
this.viewConfiguration = viewConfiguration;
this.oAuth2Configuration = oAuth2Configuration;
this.urlPattern = urlPattern;
this.contextRoot = contextRoot;
}

@GET
public SwaggerView get() {
return new SwaggerView(contextRoot, urlPattern, viewConfiguration, oAuth2Configuration);
return new SwaggerView(viewConfiguration, oAuth2Configuration);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,75 +17,25 @@

import io.dropwizard.views.View;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable;

/**
* Serves the content of Swagger's index page which has been "templatized" to support replacing the
* directory in which Swagger's static content is located (i.e. JS files) and the path with which
* requests to resources need to be prefixed.
* Serves the content of Swagger's index page which has been "templatized" to support dynamic
* configuration of Swagger UI. The template calculates paths dynamically from the browser URL,
* enabling the application to work behind proxies with different path prefixes.
*/
public class SwaggerView extends View {

private static final String SWAGGER_URI_PATH = "/swagger-static";

private final String swaggerAssetsPath;
private final String contextPath;

private final SwaggerViewConfiguration viewConfiguration;
private final SwaggerOAuth2Configuration oauth2Configuration;

public SwaggerView(
final String contextRoot,
final String urlPattern,
final SwaggerViewConfiguration viewConfiguration,
final SwaggerOAuth2Configuration oauth2Configuration) {
super(viewConfiguration.getTemplateUrl(), StandardCharsets.UTF_8);

String contextRootPrefix = "/".equals(contextRoot) ? "" : contextRoot;

// swagger-static should be found on the root context
if (!contextRootPrefix.isEmpty()) {
swaggerAssetsPath = contextRootPrefix + SWAGGER_URI_PATH;
} else {
swaggerAssetsPath =
(urlPattern.equals("/") ? SWAGGER_URI_PATH : (urlPattern + SWAGGER_URI_PATH));
}

contextPath = urlPattern.equals("/") ? contextRootPrefix : (contextRootPrefix + urlPattern);

this.viewConfiguration = viewConfiguration;
this.oauth2Configuration = oauth2Configuration;
}

/**
* Returns the title for the browser header
*
* @return String
*/
@Nullable
public String getTitle() {
return viewConfiguration.getPageTitle();
}

/**
* Returns the path with which all requests for Swagger's static content need to be prefixed
*
* @return String
*/
public String getSwaggerAssetsPath() {
return swaggerAssetsPath;
}

/**
* Returns the path with with which all requests made by Swagger's UI to Resources need to be
* prefixed
*
* @return String
*/
public String getContextPath() {
return contextPath;
}

/** @return {@link SwaggerViewConfiguration} containing every properties to customize swagger */
public SwaggerViewConfiguration getViewConfiguration() {
return viewConfiguration;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,72 @@
<#--

Copyright © 2021 Vector Pro (teamvectorpro@googlegroups.com)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-->
<#-- @ftlvariable name="" type="SwaggerView" -->
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${viewConfiguration.pageTitle}</title>
<link rel="stylesheet" type="text/css" href="${swaggerAssetsPath}/swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="${swaggerAssetsPath}/index.css" />
<link rel="icon" type="image/png" href="${swaggerAssetsPath}/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="${swaggerAssetsPath}/favicon-16x16.png" sizes="16x16" />
<script>
// Calculate contextPath dynamically from browser URL
// Example: example.com/path1/swagger -> contextPath = /path1
(function() {
var pathname = window.location.pathname;
// Remove trailing slash if present (IE11 compatible)
if (pathname.charAt(pathname.length - 1) === '/') {
pathname = pathname.slice(0, -1);
}
// Remove last segment (e.g., "swagger")
var lastSlashIndex = pathname.lastIndexOf('/');
var contextPath = lastSlashIndex > 0 ? pathname.substring(0, lastSlashIndex) : '';
// Calculate swaggerAssetsPath
var swaggerAssetsPath = contextPath + '/swagger-static';

// Calculate dynamic server URL for API requests
var dynamicServerUrl = window.location.origin + contextPath;

// Store in global scope for later use
window.swaggerContextPath = contextPath;
window.swaggerAssetsPath = swaggerAssetsPath;
window.swaggerDynamicServerUrl = dynamicServerUrl;

// Dynamically write stylesheet and favicon links
document.write('<link rel="stylesheet" type="text/css" href="' + swaggerAssetsPath + '/swagger-ui.css" />');
document.write('<link rel="stylesheet" type="text/css" href="' + swaggerAssetsPath + '/index.css" />');
document.write('<link rel="icon" type="image/png" href="' + swaggerAssetsPath + '/favicon-32x32.png" sizes="32x32" />');
document.write('<link rel="icon" type="image/png" href="' + swaggerAssetsPath + '/favicon-16x16.png" sizes="16x16" />');
})();
</script>
</head>

<body>
<div id="swagger-ui"></div>
<script src="${swaggerAssetsPath}/swagger-ui-bundle.js"> </script>
<script src="${swaggerAssetsPath}/swagger-ui-standalone-preset.js"> </script>
<script src="${swaggerAssetsPath}/swagger-snippet-generator.min.js"> </script>
<script>
// Dynamically write script tags using calculated swaggerAssetsPath
document.write('<script src="' + window.swaggerAssetsPath + '/swagger-ui-bundle.js"><\/script>');
document.write('<script src="' + window.swaggerAssetsPath + '/swagger-ui-standalone-preset.js"><\/script>');
document.write('<script src="' + window.swaggerAssetsPath + '/swagger-snippet-generator.min.js"><\/script>');
</script>

<script>
window.onload = function() {
var contextPath = window.swaggerContextPath;
var dynamicServerUrl = window.swaggerDynamicServerUrl;

const snippetTargets = [
<#list viewConfiguration.codeSnippetTargets as target>
Expand All @@ -28,7 +76,7 @@

// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "${contextPath}/swagger.json",
url: contextPath + "/swagger.json",
<#if viewConfiguration.validatorUrl??>
validatorUrl: "${viewConfiguration.validatorUrl}",
<#else>
Expand All @@ -47,9 +95,39 @@
SwaggerUIBundle.plugins.DownloadUrl,
SwaggerSnippetGenerator(snippetTargets)
],
oauth2RedirectUrl: window.location.protocol + "//" + window.location.host + "${contextPath}/oauth2-redirect.html",
oauth2RedirectUrl: window.location.protocol + "//" + window.location.host + contextPath + "/oauth2-redirect.html",
layout: "StandaloneLayout",
requestSnippetsEnabled: true
requestSnippetsEnabled: true,
// Callback when Swagger UI finishes loading the spec
onComplete: function() {
try {
// Get the current spec from Swagger UI's state
var state = ui.getState();
if (state && state.getIn) {
var specJs = state.getIn(['spec', 'json']);
if (specJs && specJs.toJS) {
var spec = specJs.toJS();
if (spec) {
// Create dynamic server entry based on current browser URL
var dynamicServer = { url: dynamicServerUrl };
// Get existing servers or empty array
var existingServers = Array.isArray(spec.servers) ? spec.servers : [];
// Only add if not already present
var alreadyExists = existingServers.some(function(s) { return s.url === dynamicServerUrl; });
if (!alreadyExists) {
// Prepend dynamic server to make it the default selection
var newServers = [dynamicServer].concat(existingServers);
// Update spec with new servers
spec.servers = newServers;
ui.specActions.updateJsonSpec(spec);
}
}
}
}
} catch (e) {
console.warn('Failed to inject dynamic server URL:', e);
}
}
});

ui.initOAuth({
Expand Down
Loading