Skip to content

Commit 49fbff3

Browse files
committed
Changes report: Add ServerBaseUrlCustomizer functionality to be able to customize the generated Server URL. Fixes springdoc#1543.
1 parent d061b3a commit 49fbff3

File tree

4 files changed

+113
-9
lines changed

4 files changed

+113
-9
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import org.springdoc.core.customizers.OpenApiCustomizer;
5858
import org.springdoc.core.customizers.OperationCustomizer;
5959
import org.springdoc.core.customizers.PropertyCustomizer;
60+
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
6061
import org.springdoc.core.models.GroupedOpenApi;
6162
import org.springdoc.core.parsers.ReturnTypeParser;
6263
import org.springdoc.core.properties.SpringDocConfigProperties;
@@ -225,7 +226,7 @@ PolymorphicModelConverter polymorphicModelConverter() {
225226
* @param securityParser the security parser
226227
* @param springDocConfigProperties the spring doc config properties
227228
* @param propertyResolverUtils the property resolver utils
228-
* @param openApiBuilderCustomisers the open api builder customisers
229+
* @param openApiBuilderCustomizers the open api builder customisers
229230
* @return the open api builder
230231
*/
231232
@Bean
@@ -234,8 +235,9 @@ PolymorphicModelConverter polymorphicModelConverter() {
234235
OpenAPIService openAPIBuilder(Optional<OpenAPI> openAPI,
235236
SecurityService securityParser,
236237
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
237-
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers) {
238-
return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers);
238+
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
239+
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers) {
240+
return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomisers);
239241
}
240242

241243
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.springdoc.core.customizers;
2+
3+
/**
4+
* The interface Server Base URL customiser.
5+
* @author skylar-stark
6+
*/
7+
@FunctionalInterface
8+
public interface ServerBaseUrlCustomizer {
9+
10+
/**
11+
* Customise.
12+
*
13+
* @param serverBaseUrl the serverBaseUrl.
14+
* @return the customised serverBaseUrl
15+
*/
16+
String customize(String serverBaseUrl);
17+
}

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import org.slf4j.Logger;
6666
import org.slf4j.LoggerFactory;
6767
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
68+
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
6869
import org.springdoc.core.properties.SpringDocConfigProperties;
6970
import org.springdoc.core.utils.PropertyResolverUtils;
7071

@@ -125,6 +126,11 @@ public class OpenAPIService implements ApplicationContextAware {
125126
*/
126127
private final Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers;
127128

129+
/**
130+
* The server base URL customisers.
131+
*/
132+
private final Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers;
133+
128134
/**
129135
* The Spring doc config properties.
130136
*/
@@ -189,11 +195,11 @@ public class OpenAPIService implements ApplicationContextAware {
189195
* @param securityParser the security parser
190196
* @param springDocConfigProperties the spring doc config properties
191197
* @param propertyResolverUtils the property resolver utils
192-
* @param openApiBuilderCustomisers the open api builder customisers
198+
* @param openApiBuilderCustomizers the open api builder customisers
193199
*/
194200
public OpenAPIService(Optional<OpenAPI> openAPI, SecurityService securityParser,
195201
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
196-
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers) {
202+
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers, Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers) {
197203
if (openAPI.isPresent()) {
198204
this.openAPI = openAPI.get();
199205
if (this.openAPI.getComponents() == null)
@@ -206,7 +212,8 @@ public OpenAPIService(Optional<OpenAPI> openAPI, SecurityService securityParser,
206212
this.propertyResolverUtils=propertyResolverUtils;
207213
this.securityParser = securityParser;
208214
this.springDocConfigProperties = springDocConfigProperties;
209-
this.openApiBuilderCustomisers = openApiBuilderCustomisers;
215+
this.openApiBuilderCustomisers = openApiBuilderCustomizers;
216+
this.serverBaseUrlCustomizers = serverBaseUrlCustomizers;
210217
if (springDocConfigProperties.isUseFqn())
211218
TypeNameResolver.std.setUseFqn(true);
212219
}
@@ -472,7 +479,16 @@ public Schema resolveProperties(Schema schema, Locale locale) {
472479
* @param serverBaseUrl the server base url
473480
*/
474481
public void setServerBaseUrl(String serverBaseUrl) {
475-
this.serverBaseUrl = serverBaseUrl;
482+
String customServerBaseUrl = serverBaseUrl;
483+
484+
if (serverBaseUrlCustomizers != null && serverBaseUrlCustomizers.isPresent()) {
485+
for (ServerBaseUrlCustomizer customiser : serverBaseUrlCustomizers.get()) {
486+
customServerBaseUrl = customiser.customize(customServerBaseUrl);
487+
}
488+
}
489+
490+
this.serverBaseUrl = customServerBaseUrl;
491+
476492
}
477493

478494
/**

springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
package org.springdoc.api;
2222

23+
import java.util.ArrayList;
2324
import java.util.HashMap;
2425
import java.util.List;
2526
import java.util.Locale;
@@ -43,6 +44,7 @@
4344
import org.mockito.junit.jupiter.MockitoExtension;
4445
import org.springdoc.core.customizers.OpenApiCustomizer;
4546
import org.springdoc.core.customizers.OperationCustomizer;
47+
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
4648
import org.springdoc.core.filters.OpenApiMethodFilter;
4749
import org.springdoc.core.fn.RouterOperation;
4850
import org.springdoc.core.properties.SpringDocConfigProperties;
@@ -68,6 +70,7 @@
6870
import static org.mockito.Mockito.when;
6971
import static org.springframework.web.bind.annotation.RequestMethod.GET;
7072

73+
7174
@ExtendWith(MockitoExtension.class)
7275
class AbstractOpenApiResourceTest {
7376

@@ -111,6 +114,7 @@ public void setUp() {
111114
openAPI = new OpenAPI();
112115
openAPI.setPaths(new Paths().addPathItem(PATH, new PathItem()));
113116
ReflectionTestUtils.setField(openAPIService, "cachedOpenAPI", new HashMap<>());
117+
ReflectionTestUtils.setField(openAPIService, "serverBaseUrlCustomizers", Optional.empty());
114118

115119
when(openAPIService.getCalculatedOpenAPI()).thenReturn(openAPI);
116120
when(openAPIService.getContext()).thenReturn(context);
@@ -187,7 +191,7 @@ void preLoadingModeShouldNotOverwriteServers() throws InterruptedException {
187191

188192
String customUrl = "https://custom.com";
189193
String generatedUrl = "https://generated.com";
190-
OpenApiCustomizer openApiCustomizer = openApi -> openApi.setServers(singletonList(new Server().url(customUrl)));
194+
OpenApiCustomizer openApiCustomiser = openApi -> openApi.setServers(singletonList(new Server().url(customUrl)));
191195
SpringDocConfigProperties properties = new SpringDocConfigProperties();
192196
properties.setPreLoadingEnabled(true);
193197

@@ -198,7 +202,7 @@ void preLoadingModeShouldNotOverwriteServers() throws InterruptedException {
198202
responseBuilder,
199203
operationParser,
200204
Optional.empty(),
201-
Optional.of(singletonList(openApiCustomizer)),
205+
Optional.of(singletonList(openApiCustomiser)),
202206
Optional.empty(),
203207
properties, springDocProviders
204208
);
@@ -215,6 +219,71 @@ void preLoadingModeShouldNotOverwriteServers() throws InterruptedException {
215219
assertThat(after.getServers().get(0).getUrl(), is(customUrl));
216220
}
217221

222+
@Test
223+
void serverBaseUrlCustomisersTest() throws InterruptedException {
224+
when(openAPIService.updateServers(any())).thenCallRealMethod();
225+
when(openAPIService.getCachedOpenAPI(any())).thenCallRealMethod();
226+
doAnswer(new CallsRealMethods()).when(openAPIService).setServerBaseUrl(any());
227+
doAnswer(new CallsRealMethods()).when(openAPIService).setCachedOpenAPI(any(), any());
228+
229+
SpringDocConfigProperties properties = new SpringDocConfigProperties();
230+
properties.setPreLoadingEnabled(true);
231+
232+
resource = new EmptyPathsOpenApiResource(
233+
GROUP_NAME,
234+
openAPIBuilderObjectFactory,
235+
requestBuilder,
236+
responseBuilder,
237+
operationParser,
238+
Optional.empty(),
239+
Optional.empty(),
240+
Optional.empty(),
241+
properties,
242+
springDocProviders
243+
);
244+
245+
// wait for executor to be done
246+
Thread.sleep(1_000);
247+
248+
Locale locale = Locale.US;
249+
250+
// Test that setting generated URL works fine with no customizers present
251+
String generatedUrl = "https://generated-url.com/context-path";
252+
openAPIService.setServerBaseUrl(generatedUrl);
253+
openAPIService.updateServers(openAPI);
254+
OpenAPI after = resource.getOpenApi(locale);
255+
assertThat(after.getServers().get(0).getUrl(), is(generatedUrl));
256+
257+
// Test that adding a serverBaseUrlCustomizer has the desired effect
258+
ServerBaseUrlCustomizer serverBaseUrlCustomizer = serverBaseUrl -> serverBaseUrl.replace("/context-path", "");
259+
List<ServerBaseUrlCustomizer> serverBaseUrlCustomizerList = new ArrayList<>();
260+
serverBaseUrlCustomizerList.add(serverBaseUrlCustomizer);
261+
262+
ReflectionTestUtils.setField(openAPIService, "serverBaseUrlCustomizers", Optional.of(serverBaseUrlCustomizerList));
263+
openAPIService.setServerBaseUrl(generatedUrl);
264+
openAPIService.updateServers(openAPI);
265+
after = resource.getOpenApi(locale);
266+
assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com"));
267+
268+
// Test that serverBaseUrlCustomisers are performed in order
269+
generatedUrl = "https://generated-url.com/context-path/second-path";
270+
ServerBaseUrlCustomizer serverBaseUrlCustomiser2 = serverBaseUrl -> serverBaseUrl.replace("/context-path/second-path", "");
271+
serverBaseUrlCustomizerList.add(serverBaseUrlCustomiser2);
272+
273+
openAPIService.setServerBaseUrl(generatedUrl);
274+
openAPIService.updateServers(openAPI);
275+
after = resource.getOpenApi(locale);
276+
assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com/second-path"));
277+
278+
// Test that all serverBaseUrlCustomisers in the List are performed
279+
ServerBaseUrlCustomizer serverBaseUrlCustomiser3 = serverBaseUrl -> serverBaseUrl.replace("/second-path", "");
280+
serverBaseUrlCustomizerList.add(serverBaseUrlCustomiser3);
281+
282+
openAPIService.setServerBaseUrl(generatedUrl);
283+
openAPIService.updateServers(openAPI);
284+
after = resource.getOpenApi(locale);
285+
assertThat(after.getServers().get(0).getUrl(), is("https://generated-url.com"));
286+
}
218287

219288
private static class EmptyPathsOpenApiResource extends AbstractOpenApiResource {
220289

0 commit comments

Comments
 (0)