Skip to content

make validatorUrl configurable and fix overwrites #281

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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 18, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public final class Constants {
public static final String SPRINGDOC_ACTUATOR_TAG = "Actuator";
public static final String DEFAULT_WEB_JARS_PREFIX_URL = "/webjars";
public static final String WEB_JARS_PREFIX_URL = "${springdoc.webjars.prefix:#{T(org.springdoc.core.Constants).DEFAULT_WEB_JARS_PREFIX_URL}}";
public static final String SWAGGER_UI_URL = "/swagger-ui/index.html?url=";
public static final String DEFAULT_VALIDATOR_URL = "&validatorUrl=";
public static final String SWAGGER_UI_URL = "/swagger-ui/index.html";
public static final String DEFAULT_VALIDATOR_URL = "";
public static final String APPLICATION_OPENAPI_YAML = "application/vnd.oai.openapi";
public static final String DEFAULT_SWAGGER_UI_PATH = DEFAULT_PATH_SEPARATOR + "swagger-ui.html";
public static final String SWAGGER_UI_PATH = "${springdoc.swagger-ui.path:#{T(org.springdoc.core.Constants).DEFAULT_SWAGGER_UI_PATH}}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
@Configuration
@ConfigurationProperties(prefix = "springdoc.swagger-ui")
public class SwaggerUiConfigProperties {

public static final String CONFIG_URL_PROPERTY = "configUrl";
public static final String VALIDATOR_URL_PROPERTY = "validatorUrl";
public static final String URL_PROPERTY = "url";

/**
* The path for the Swagger UI pages to load. Will redirect to the springdoc.webjars.prefix property.
*/
Expand All @@ -31,6 +36,11 @@ public class SwaggerUiConfigProperties {
* URL to fetch external configuration document from.
*/
private String configUrl;

/**
* URL to validate specs against.
*/
private String validatorUrl;
/**
* If set, enables filtering. The top bar will show an edit box that
* could be used to filter the tagged operations that are shown.
Expand Down Expand Up @@ -104,7 +114,8 @@ public class SwaggerUiConfigProperties {
public Map<String, String> getConfigParameters() {
final Map<String, String> params = new TreeMap<>();
put("layout", layout, params);
put("configUrl", configUrl, params);
put(CONFIG_URL_PROPERTY, configUrl, params);
put(VALIDATOR_URL_PROPERTY, validatorUrl, params);
put("filter", filter, params);
put("deepLinking", this.deepLinking, params);
put("displayOperationId", displayOperationId, params);
Expand Down Expand Up @@ -142,6 +153,14 @@ protected void put(final String name, final String value, final Map<String, Stri
}
}

public String getValidatorUrl() {
return validatorUrl;
}

public void setValidatorUrl(String validatorUrl) {
this.validatorUrl = validatorUrl;
}

public String getPath() {
return path;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.springdoc.core;

import org.springframework.web.util.UriComponentsBuilder;

import java.util.Map;

import static org.springdoc.core.Constants.DEFAULT_VALIDATOR_URL;
import static org.springdoc.core.SwaggerUiConfigProperties.*;

final public class SwaggerUiQueryParamsAppender {

private SwaggerUiQueryParamsAppender() {
}

/**
* Appends swagger-ui query-params to the provided builder.
* <p>
* Since url is derived from springdoc-endpoint it can be provided independently of swaggerUiParams.
* If configUrl is used, config has to be provided manually including `url`, `validatorUrl`
*
* @param uriBuilder the UriComponentsBuilder to which queryParams get appended
* @param swaggerUiParams a map of the swaggerUiParams to use
* @param url the url to use as queryParameter (gets derived from springdoc properties
* @return UriComponentsBuilder with appended swagger-ui query-parameters
*/
public static UriComponentsBuilder appendSwaggerUiQueryParams(final UriComponentsBuilder uriBuilder,
final Map<String, String> swaggerUiParams,
final String url) {
if (swaggerUiParams.get(CONFIG_URL_PROPERTY) == null) {
uriBuilder.queryParam(URL_PROPERTY, url);

if (swaggerUiParams.get(VALIDATOR_URL_PROPERTY) == null) {
uriBuilder.queryParam(VALIDATOR_URL_PROPERTY, DEFAULT_VALIDATOR_URL);
}
}
return appendQueryParameter(uriBuilder, swaggerUiParams);
}

private static UriComponentsBuilder appendQueryParameter(UriComponentsBuilder uriBuilder,
Map<String, String> swaggerUiParams) {

return swaggerUiParams.entrySet().stream()
.reduce(uriBuilder,
(b, e) -> b.queryParam(e.getKey(), e.getValue()),
(left, right) -> left);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.Map;

import static org.springdoc.core.Constants.*;
import static org.springdoc.core.SwaggerUiQueryParamsAppender.appendSwaggerUiQueryParams;
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
import static org.springframework.web.servlet.view.UrlBasedViewResolver.REDIRECT_URL_PREFIX;

Expand Down Expand Up @@ -47,25 +48,19 @@ public String redirectToUi(HttpServletRequest request) {
sbUrl.append(mvcServletPath);
sbUrl.append(uiRootPath);
sbUrl.append(SWAGGER_UI_URL);
if (contextPath.endsWith(DEFAULT_PATH_SEPARATOR)) {
contextPath = contextPath.substring(0, contextPath.length() - 1);
sbUrl.append(contextPath).append(apiDocsUrl);
} else {
sbUrl.append(contextPath).append(apiDocsUrl);
}
sbUrl.append(DEFAULT_VALIDATOR_URL);

final Map<String, String> params = swaggerUiConfig.getConfigParameters();
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(sbUrl.toString());
Map<String, String> swaggerUiParams = swaggerUiConfig.getConfigParameters();
String url = buildUrl(contextPath, apiDocsUrl);

final UriComponentsBuilder builder = params
.entrySet()
.stream()
.reduce(
UriComponentsBuilder
.fromUriString(sbUrl.toString()),
(b, e) -> b.queryParam(e.getKey(), e.getValue()),
(left, right) -> left);
return appendSwaggerUiQueryParams(uriBuilder, swaggerUiParams, url)
.build().encode().toString();
}

return builder.build().encode().toString();
private String buildUrl(final String contextPath, final String docsUrl) {
if (contextPath.endsWith(DEFAULT_PATH_SEPARATOR)) {
return contextPath.substring(0, contextPath.length() - 1) + docsUrl;
}
return contextPath + docsUrl;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package test.org.springdoc.ui.app1;

import org.junit.Test;
import org.springdoc.core.SwaggerUiConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MvcResult;
import test.org.springdoc.ui.AbstractSpringDocTest;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest(properties = {
"springdoc.swagger-ui.configUrl=/foo/bar",
"springdoc.swagger-ui.url=/batz" // ignored since configUrl is configured
})
public class SpringDocApp1RedirectConfigUrlTest extends AbstractSpringDocTest {

@Test
public void shouldRedirectWithConfigUrlIgnoringQueryParams() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/swagger-ui.html"))
.andExpect(status().isFound()).andReturn();

String locationHeader = mvcResult.getResponse().getHeader("Location");
assertEquals("/swagger-ui/index.html?configUrl=/foo/bar", locationHeader);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package test.org.springdoc.ui.app1;

import org.junit.Test;
import org.springframework.test.web.servlet.MvcResult;
import test.org.springdoc.ui.AbstractSpringDocTest;

import static org.junit.Assert.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

public class SpringDocApp1RedirectDefaultTest extends AbstractSpringDocTest {

@Test
public void shouldRedirectWithDefaultQueryParams() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/swagger-ui.html"))
.andExpect(status().isFound()).andReturn();

String locationHeader = mvcResult.getResponse().getHeader("Location");
assertEquals("/swagger-ui/index.html?url=/v3/api-docs&validatorUrl=", locationHeader);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package test.org.springdoc.ui.app1;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MvcResult;
import test.org.springdoc.ui.AbstractSpringDocTest;

import static org.junit.Assert.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest(properties = {
"springdoc.swagger-ui.validatorUrl=/foo/validate",
"springdoc.api-docs.path=/baf/batz"
})
public class SpringDocApp1RedirectWithConfigTest extends AbstractSpringDocTest {

@Test
public void shouldRedirectWithConfiguredParams() throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/swagger-ui.html"))
.andExpect(status().isFound()).andReturn();

String locationHeader = mvcResult.getResponse().getHeader("Location");
assertEquals("/swagger-ui/index.html?url=/baf/batz&validatorUrl=/foo/validate", locationHeader);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.Map;

import static org.springdoc.core.Constants.*;
import static org.springdoc.core.SwaggerUiQueryParamsAppender.appendSwaggerUiQueryParams;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;

Expand All @@ -38,23 +39,11 @@ public class SwaggerWelcome {
@Bean
@ConditionalOnProperty(name = SPRINGDOC_SWAGGER_UI_ENABLED, matchIfMissing = true)
RouterFunction<ServerResponse> routerFunction() {
String url = webJarsPrefixUrl +
SWAGGER_UI_URL +
apiDocsUrl +
DEFAULT_VALIDATOR_URL;

final Map<String, String> params = swaggerUiConfig.getConfigParameters();


final UriComponentsBuilder builder = params
.entrySet()
.stream()
.reduce(
UriComponentsBuilder
.fromUriString(url),
(b, e) -> b.queryParam(e.getKey(), e.getValue()),
(left, right) -> left);
String baseUrl = webJarsPrefixUrl + SWAGGER_UI_URL;

final Map<String, String> swaggerUiParams = swaggerUiConfig.getConfigParameters();
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(baseUrl);
final UriComponentsBuilder builder = appendSwaggerUiQueryParams(uriBuilder, swaggerUiParams, apiDocsUrl);

return route(GET(uiPath),
req -> ServerResponse.temporaryRedirect(URI.create(builder.build().encode().toString())).build());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package test.org.springdoc.ui.app1;

import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springdoc.core.SwaggerUiConfigProperties;
import org.springdoc.ui.SwaggerWelcome;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;


@RunWith(SpringRunner.class)
@WebFluxTest(properties = {
"springdoc.swagger-ui.configUrl=/foo/bar",
"springdoc.swagger-ui.url=/batz" // ignored since configUrl is configured
})
@ActiveProfiles("test")
@ContextConfiguration(classes = {SwaggerWelcome.class, SwaggerUiConfigProperties.class})
public class SpringDocApp1RedirectConfigUrlTest {

@Autowired
private WebTestClient webTestClient;

@Test
public void shouldRedirectWithConfigUrlIgnoringQueryParams() throws Exception {

WebTestClient.ResponseSpec responseSpec = webTestClient.get().uri("/swagger-ui.html").exchange()
.expectStatus().isTemporaryRedirect();
responseSpec.expectHeader()
.value("Location", Matchers.is("/webjars/swagger-ui/index.html?configUrl=/foo/bar"));

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package test.org.springdoc.ui.app1;

import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springdoc.core.SwaggerUiConfigProperties;
import org.springdoc.ui.SwaggerWelcome;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;


@RunWith(SpringRunner.class)
@WebFluxTest()
@ActiveProfiles("test")
@ContextConfiguration(classes = {SwaggerWelcome.class, SwaggerUiConfigProperties.class})
public class SpringDocApp1RedirectDefaultTest {

@Autowired
private WebTestClient webTestClient;

@Test
public void shouldRedirectWithDefaultQueryParams() throws Exception {
WebTestClient.ResponseSpec responseSpec = webTestClient.get().uri("/swagger-ui.html").exchange()
.expectStatus().isTemporaryRedirect();
responseSpec.expectHeader()
.value("Location", Matchers.is("/webjars/swagger-ui/index.html?url=/v3/api-docs&validatorUrl="));

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package test.org.springdoc.ui.app1;

import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springdoc.core.SwaggerUiConfigProperties;
import org.springdoc.ui.SwaggerWelcome;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

@RunWith(SpringRunner.class)
@WebFluxTest(properties = {
"springdoc.swagger-ui.validatorUrl=/foo/validate",
"springdoc.api-docs.path=/baf/batz"
})
@ActiveProfiles("test")
@ContextConfiguration(classes = {SwaggerWelcome.class, SwaggerUiConfigProperties.class})
public class SpringDocApp1RedirectWithConfigTest {
@Autowired
private WebTestClient webTestClient;

@Test
public void shouldRedirectWithConfiguredParams() throws Exception {
WebTestClient.ResponseSpec responseSpec = webTestClient.get().uri("/swagger-ui.html").exchange()
.expectStatus().isTemporaryRedirect();

responseSpec.expectHeader()
.value("Location", Matchers.is("/webjars/swagger-ui/index.html?url=/baf/batz&validatorUrl=/foo/validate"));
}

}