Skip to content

Add ServerBaseUrlCustomizer functionality to be able to customize the generated Server URL #1543

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 2 commits into from
Mar 22, 2022
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 @@ -62,7 +62,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;

import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
Expand Down Expand Up @@ -120,6 +120,11 @@ public class OpenAPIService implements ApplicationContextAware {
*/
private final Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers;

/**
* The server base URL customisers.
*/
private final Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers;

Choose a reason for hiding this comment

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

Weird pattern to use Optional for class vars when the code has to check if it's null anyway.


/**
* The Spring doc config properties.
*/
Expand Down Expand Up @@ -188,7 +193,8 @@ public class OpenAPIService implements ApplicationContextAware {
*/
OpenAPIService(Optional<OpenAPI> openAPI, SecurityService securityParser,
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers) {
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers) {
if (openAPI.isPresent()) {
this.openAPI = openAPI.get();
if (this.openAPI.getComponents() == null)
Expand All @@ -202,6 +208,7 @@ public class OpenAPIService implements ApplicationContextAware {
this.securityParser = securityParser;
this.springDocConfigProperties = springDocConfigProperties;
this.openApiBuilderCustomisers = openApiBuilderCustomisers;
this.serverBaseUrlCustomisers = serverBaseUrlCustomisers;
if (springDocConfigProperties.isUseFqn())
TypeNameResolver.std.setUseFqn(true);
}
Expand Down Expand Up @@ -466,7 +473,15 @@ public Schema resolveProperties(Schema schema, Locale locale) {
* @param serverBaseUrl the server base url
*/
public void setServerBaseUrl(String serverBaseUrl) {
this.serverBaseUrl = serverBaseUrl;
String customServerBaseUrl = serverBaseUrl;

if (serverBaseUrlCustomisers != null && serverBaseUrlCustomisers.isPresent()) {
for (ServerBaseUrlCustomizer customiser : serverBaseUrlCustomisers.get()) {
customServerBaseUrl = customiser.customise(customServerBaseUrl);
}
}

this.serverBaseUrl = customServerBaseUrl;
}

/**
Expand Down Expand Up @@ -808,8 +823,17 @@ public SecurityService getSecurityParser() {
return securityParser;
}

/**
* Gets server base URL
*
* @return the server base URL
*/
public String getServerBaseUrl() {
return serverBaseUrl;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.customizers.PropertyCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.providers.ActuatorProvider;
import org.springdoc.core.providers.CloudFunctionProvider;
import org.springdoc.core.providers.JavadocProvider;
Expand Down Expand Up @@ -225,8 +226,9 @@ PolymorphicModelConverter polymorphicModelConverter() {
OpenAPIService openAPIBuilder(Optional<OpenAPI> openAPI,
SecurityService securityParser,
SpringDocConfigProperties springDocConfigProperties,PropertyResolverUtils propertyResolverUtils,
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers) {
return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers);
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers) {
return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers);
}

/**
Expand Down Expand Up @@ -579,4 +581,4 @@ CloudFunctionProvider springCloudFunctionProvider(Optional<FunctionCatalog> func
return new SpringCloudFunctionProvider(functionCatalog, genericResponseService, springDocConfigProperties);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.springdoc.core.customizers;

/**
* The interface Server Base URL customiser.
* @author skylar-stark
*/
@FunctionalInterface
public interface ServerBaseUrlCustomizer {

/**
* Customise.
*
* @param serverBaseUrl the serverBaseUrl.
* @return the customised serverBaseUrl
*/
public String customise(String serverBaseUrl);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package org.springdoc.api;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -49,6 +50,7 @@
import org.springdoc.core.SpringDocProviders;
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.filters.OpenApiMethodFilter;
import org.springdoc.core.fn.RouterOperation;

Expand Down Expand Up @@ -111,6 +113,7 @@ public void setUp() {
openAPI = new OpenAPI();
openAPI.setPaths(new Paths().addPathItem(PATH, new PathItem()));
ReflectionTestUtils.setField(openAPIService, "cachedOpenAPI", new HashMap<>());
ReflectionTestUtils.setField(openAPIService, "serverBaseUrlCustomisers", Optional.empty());

when(openAPIService.getCalculatedOpenAPI()).thenReturn(openAPI);
when(openAPIService.getContext()).thenReturn(context);
Expand Down Expand Up @@ -215,6 +218,71 @@ void preLoadingModeShouldNotOverwriteServers() throws InterruptedException {
assertThat(after.getServers().get(0).getUrl(), is(customUrl));
}

@Test
void serverBaseUrlCustomisersTest() throws InterruptedException {
when(openAPIService.updateServers(any())).thenCallRealMethod();
when(openAPIService.getCachedOpenAPI(any())).thenCallRealMethod();
doAnswer(new CallsRealMethods()).when(openAPIService).setServerBaseUrl(any());
doAnswer(new CallsRealMethods()).when(openAPIService).setCachedOpenAPI(any(), any());

SpringDocConfigProperties properties = new SpringDocConfigProperties();
properties.setPreLoadingEnabled(true);

resource = new EmptyPathsOpenApiResource(
GROUP_NAME,
openAPIBuilderObjectFactory,
requestBuilder,
responseBuilder,
operationParser,
Optional.empty(),
Optional.empty(),
Optional.empty(),
properties,
springDocProviders
);

// wait for executor to be done
Thread.sleep(1_000);

Locale locale = Locale.US;

// Test that setting generated URL works fine with no customisers present
String generatedUrl = "https://generated-url.com/context-path";
openAPIService.setServerBaseUrl(generatedUrl);
openAPIService.updateServers(openAPI);
OpenAPI after = resource.getOpenApi(locale);
assertThat(after.getServers().get(0).getUrl(), is(generatedUrl));

// Test that adding a serverBaseUrlCustomiser has the desired effect
ServerBaseUrlCustomizer serverBaseUrlCustomiser = serverBaseUrl -> serverBaseUrl.replace("/context-path", "");
List<ServerBaseUrlCustomizer> serverBaseUrlCustomiserList = new ArrayList<>();
serverBaseUrlCustomiserList.add(serverBaseUrlCustomiser);

ReflectionTestUtils.setField(openAPIService, "serverBaseUrlCustomisers", Optional.of(serverBaseUrlCustomiserList));
openAPIService.setServerBaseUrl(generatedUrl);
openAPIService.updateServers(openAPI);
after = resource.getOpenApi(locale);
assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com"));

// Test that serverBaseUrlCustomisers are performed in order
generatedUrl = "https://generated-url.com/context-path/second-path";
ServerBaseUrlCustomizer serverBaseUrlCustomiser2 = serverBaseUrl -> serverBaseUrl.replace("/context-path/second-path", "");
serverBaseUrlCustomiserList.add(serverBaseUrlCustomiser2);

openAPIService.setServerBaseUrl(generatedUrl);
openAPIService.updateServers(openAPI);
after = resource.getOpenApi(locale);
assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com/second-path"));

// Test that all serverBaseUrlCustomisers in the List are performed
ServerBaseUrlCustomizer serverBaseUrlCustomiser3 = serverBaseUrl -> serverBaseUrl.replace("/second-path", "");
serverBaseUrlCustomiserList.add(serverBaseUrlCustomiser3);

openAPIService.setServerBaseUrl(generatedUrl);
openAPIService.updateServers(openAPI);
after = resource.getOpenApi(locale);
assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com"));
}

private static class EmptyPathsOpenApiResource extends AbstractOpenApiResource {

Expand Down