Skip to content

Commit

Permalink
feat(core): make springwolf ui path configurable (#786)
Browse files Browse the repository at this point in the history
* feat(core): make springwolf ui path configurable

Co-authored-by: Timon Back <[email protected]>

* chore(core): use default values for springwolf.path.base

* chore(core): allow missing WebMvcConfigurer class in classpath

* chore(core): add integration test for custom springwolf path

Co-authored-by: Timon Back <[email protected]>

---------

Co-authored-by: Timon Back <[email protected]>
  • Loading branch information
sam0r040 and timonback authored Jun 7, 2024
1 parent dc6e019 commit d4b0edc
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 7 deletions.
1 change: 1 addition & 0 deletions springwolf-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies {
implementation "org.apache.commons:commons-lang3:${commonsLang3Version}"

compileOnly "org.springframework.boot:spring-boot-actuator"
compileOnly "org.springframework:spring-webmvc"
compileOnly "org.projectlombok:lombok:${lombokVersion}"

annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.core.configuration;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ConditionalOnClass(WebMvcConfigurer.class)
@Import(SpringwolfUiResourceConfigurer.class)
public class SpringwolfUiResourceConfiguration {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.core.configuration;

import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Configuration
@RequiredArgsConstructor
@Order(value = Ordered.HIGHEST_PRECEDENCE) // Highest so that all others will replace this configuration
public class SpringwolfUiResourceConfigurer implements WebMvcConfigurer {

private final SpringwolfConfigProperties springwolfConfigProperties;
private final WebProperties webProperties;
private final WebMvcProperties webMvcProperties;

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String springwolfBasePath = springwolfConfigProperties.getPath().getBase();

log.debug("Serving Springwolf with base-path: {}", springwolfBasePath);

registry.addResourceHandler(springwolfBasePath + "/**", webMvcProperties.getStaticPathPattern())
.addResourceLocations(buildStaticLocation());
}

private String[] buildStaticLocation() {
List<String> staticLocations =
new ArrayList<>(Arrays.asList(webProperties.getResources().getStaticLocations()));
staticLocations.add("classpath:/META-INF/resources/springwolf/");

return staticLocations.toArray(new String[0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import static io.github.springwolf.core.configuration.properties.SpringwolfConfigConstants.SPRINGWOLF_ENDPOINT_ACTUATOR_ENABLED;

/**
* Spring-Configuration defining the web controller beans.
*/
@Configuration(proxyBeanMethods = false)
@Import(SpringwolfUiResourceConfiguration.class)
public class SpringwolfWebConfiguration {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public enum InitMode {
*/
private boolean useFqn = true;

@Deprecated(forRemoval = true)
private Paths paths = new Paths();

private Path path = new Path();

@Nullable
private Endpoint endpoint;

Expand All @@ -67,6 +72,25 @@ public enum InitMode {
@Nullable
private Payload payload = new Payload();

@Getter
@Setter
public static class Paths {

/**
* Deprecated in favor of springwolf.path.docs to control
* only the sub path for the docs endpoint
*/
@Deprecated(forRemoval = true)
private String docs = "/springwolf/docs";
}

@Getter
@Setter
public static class Path {
private String base = "/springwolf";
private String docs = "/docs";
}

@Getter
@Setter
public static class ConfigDocket {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ public class AsyncApiController {
private final AsyncApiSerializerService serializer;

@GetMapping(
path = {"${springwolf.paths.docs:/springwolf/docs}", "${springwolf.paths.docs:/springwolf/docs}.json"},
path = {
"${springwolf.paths.docs:/springwolf/docs}",
"${springwolf.paths.docs:/springwolf/docs}.json",
"${springwolf.path.base:/springwolf}${springwolf.path.docs:/docs}",
"${springwolf.path.base:/springwolf}${springwolf.path.docs:/docs}.json"
},
produces = MediaType.APPLICATION_JSON_VALUE)
public String asyncApiJson() throws JsonProcessingException {
log.debug("Returning AsyncApi.json document");
Expand All @@ -28,7 +33,12 @@ public String asyncApiJson() throws JsonProcessingException {
return serializer.toJsonString(asyncAPI);
}

@GetMapping(path = "${springwolf.paths.docs:/springwolf/docs}.yaml", produces = "application/yaml")
@GetMapping(
path = {
"${springwolf.paths.docs:/springwolf/docs}.yaml",
"${springwolf.path.base:/springwolf}${springwolf.path.docs:/docs}.yaml"
},
produces = "application/yaml")
public String asyncApiYaml() throws JsonProcessingException {
log.debug("Returning AsyncApi.yaml document");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.examples.sqs;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.TestPropertySource;

import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest(
classes = {SpringwolfSqsExampleApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith({SqsTestContainerExtension.class})
@TestPropertySource(
properties = {"springwolf.path.base=/my-custom/springwolf/endpoint/test", "springwolf.path.docs=/apispec"})
class CustomPathConfigurationIntegrationTest {

@DynamicPropertySource
static void setUpTestContainers(DynamicPropertyRegistry registry) {
SqsTestContainerExtension.overrideConfiguration(registry);
}

@Autowired
private TestRestTemplate restTemplate;

@Test
void getSpec() {
String url = "/my-custom/springwolf/endpoint/test/apispec";
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);

assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
}

@Test
void canPublish() {
String url = "/my-custom/springwolf/endpoint/test/sqs/publish";
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);

assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
}

@Test
void asyncapiDocsShouldReturnTheCorrectJsonResponse() {
String url = "/my-custom/springwolf/endpoint/test/asyncapi-ui.html";
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);

assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/springwolf/amqp")
@RequestMapping("${springwolf.path.base:/springwolf}/amqp")
@Slf4j
public class SpringwolfAmqpController extends PublishingBaseController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/springwolf/jms")
@RequestMapping("${springwolf.path.base:/springwolf}/jms")
@Slf4j
public class SpringwolfJmsController extends PublishingBaseController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/springwolf/kafka")
@RequestMapping("${springwolf.path.base:/springwolf}/kafka")
@Slf4j
public class SpringwolfKafkaController extends PublishingBaseController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@Slf4j
@RestController
@RequestMapping("/springwolf/sns")
@RequestMapping("${springwolf.path.base:/springwolf}/sns")
public class SpringwolfSnsController extends PublishingBaseController {

private final SpringwolfSnsProducer producer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/springwolf/sqs")
@RequestMapping("${springwolf.path.base:/springwolf}/sqs")
@Slf4j
public class SpringwolfSqsController extends PublishingBaseController {

Expand Down

0 comments on commit d4b0edc

Please sign in to comment.