Skip to content
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

Support info extensions via environment #423

Merged
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 @@ -9,6 +9,7 @@
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.Optional;

@Slf4j
Expand Down Expand Up @@ -75,19 +76,29 @@ private AsyncApiDocket parseApplicationConfigProperties() {
return builder.build();
}

private static Info buildInfo(@Nullable SpringwolfConfigProperties.ConfigDocket.Info info) {
if (info == null || !StringUtils.hasText(info.getVersion()) || !StringUtils.hasText(info.getTitle())) {
private static Info buildInfo(@Nullable SpringwolfConfigProperties.ConfigDocket.Info configDocketInfo) {
if (configDocketInfo == null
|| !StringUtils.hasText(configDocketInfo.getVersion())
|| !StringUtils.hasText(configDocketInfo.getTitle())) {
throw new IllegalArgumentException("One or more required fields of the info object (title, version) "
+ "in application.properties with path prefix " + SpringwolfConfigConstants.SPRINGWOLF_CONFIG_PREFIX
+ " is not set.");
}

return Info.builder()
.version(info.getVersion())
.title(info.getTitle())
.description(info.getDescription())
.contact(info.getContact())
.license(info.getLicense())
Info asyncapiInfo = Info.builder()
.version(configDocketInfo.getVersion())
.title(configDocketInfo.getTitle())
.description(configDocketInfo.getDescription())
.contact(configDocketInfo.getContact())
.license(configDocketInfo.getLicense())
.build();

// copy extension fields from configDocketInfo to asyncapiInfo.
if (configDocketInfo.getExtensionFields() != null) {
Map<String, Object> extFieldsMap = Map.copyOf(configDocketInfo.getExtensionFields());
asyncapiInfo.setExtensionFields(extFieldsMap);
}

return asyncapiInfo;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ public static class Info {
@NestedConfigurationProperty
@Nullable
private License license;

/**
* Extension properties for the Info block.
*/
@Nullable
private Map<String, String> extensionFields;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class DefaultAsyncApiDocketServiceIntegrationTest {
"springwolf.enabled=true",
"springwolf.docket.info.title=Info title was loaded from spring properties",
"springwolf.docket.info.version=1.0.0",
"springwolf.docket.info.extension-fields.x-api-name=api-name",
"springwolf.docket.base-package=io.github.stavshamir.springwolf.example",
"springwolf.docket.servers.test-protocol.protocol=test",
"springwolf.docket.servers.test-protocol.url=some-server:1234"
Expand All @@ -46,6 +47,7 @@ void testDocketContentShouldBeLoadedFromProperties() {
AsyncApiDocket docket = asyncApiDocketService.getAsyncApiDocket();
assertThat(docket).isNotNull();
assertThat(docket.getInfo().getTitle()).isEqualTo("Info title was loaded from spring properties");
assertThat(docket.getInfo().getExtensionFields().get("x-api-name")).isEqualTo("api-name");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties.ConfigDocket.Info;
import org.junit.jupiter.api.Test;

import java.util.Map;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -34,6 +35,7 @@ void testServiceShouldMapAllPropertiesToTheDocket() {
info.setDescription("some-description");
info.setLicense(new License("license-name", "license-url"));
info.setContact(new Contact("contact-name", "contact-url", "contact-email"));
info.setExtensionFields(Map.of("x-api-name", "api-name"));
configDocket.setInfo(info);

SpringwolfConfigProperties properties = new SpringwolfConfigProperties();
Expand All @@ -52,6 +54,8 @@ void testServiceShouldMapAllPropertiesToTheDocket() {
assertThat(asyncApiDocket.getInfo().getDescription()).isEqualTo(info.getDescription());
assertThat(asyncApiDocket.getInfo().getLicense()).isEqualTo(info.getLicense());
assertThat(asyncApiDocket.getInfo().getContact()).isEqualTo(info.getContact());
assertThat(asyncApiDocket.getInfo().getExtensionFields().get("x-api-name"))
.isEqualTo("api-name");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

@Configuration
public class AsyncApiConfiguration {

Expand Down Expand Up @@ -50,6 +52,12 @@ public AsyncApiDocket asyncApiDocket() {
.license(License.builder().name("Apache License 2.0").build())
.build();

// the builder for asyncapi info, contact and license doesn't support setting/adding extensions, so
// we add text extension explicitely
info.setExtensionFields(Map.of("x-api-audience", "company-internal"));
info.getContact().setExtensionFields(Map.of("x-phone", "+49 123 456789"));
info.getLicense().setExtensionFields(Map.of("x-desc", "some description"));

Server amqp = Server.builder()
.protocol("amqp")
.url(String.format("%s:%s", amqpHost, amqpPort))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#########
# Spring configuration
spring.application.name=Springwolf example project - Amqp
spring.application.name=Springwolf example project - AMQP


#########
Expand All @@ -19,10 +19,13 @@ springwolf.docket.info.title=${spring.application.name}
springwolf.docket.info.version=1.0.0
springwolf.docket.info.description=Springwolf example project to demonstrate springwolfs abilities
springwolf.docket.info.terms-of-service=http://asyncapi.org/terms
springwolf.docket.info.extension-fields.x-api-audience=company-internal
springwolf.docket.info.contact.name=springwolf
[email protected]
springwolf.docket.info.contact.url=https://github.com/springwolf/springwolf-core
springwolf.docket.info.contact.extension-fields.x-phone=+49 123 456789
springwolf.docket.info.license.name=Apache License 2.0
springwolf.docket.info.license.extension-fields.x-desc=some description
springwolf.docket.servers.amqp.protocol=amqp
springwolf.docket.servers.amqp.url=${spring.rabbitmq.host}:${spring.rabbitmq.port}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.amqp;

import org.springframework.test.context.TestPropertySource;

/**
* Api integrationtest based on a SpringBoot application that defines a custom Docket bean. This contains Info and
* Server Informations as well as some explicit Producer and Consumer definitions.
*/
@TestPropertySource(properties = {"customAsyncApiDocketBean=true"})
public class ApiWithDocketBeanIntegrationTest extends BaseApiIntegrationTest {

@Override
protected String getExpectedApiFileName() {
return "/asyncapi.json";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.amqp;

import org.springframework.test.context.TestPropertySource;

/**
* Api integrationtest based on a SpringBoot application that defines all info and server properties via
* spring environment (from application.properties).
*/
@TestPropertySource(properties = {"customAsyncApiDocketBean=false"})
public class ApiWithDocketFromEnvironmentIntegrationTest extends BaseApiIntegrationTest {

@Override
protected String getExpectedApiFileName() {
return "/asyncapi_withdocketfromenvironment.json";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@

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

/**
* Api integrationtest base class defining a SpringBootTest and a test method which asserts the resulting asyncapi.
* Subclasses can customize this test with @TestPropertySources and custom expectation file names.
* @see ApiWithDocketBeanIntegrationTest
* @see ApiWithDocketFromEnvironmentIntegrationTest
*/
@SpringBootTest(
classes = {SpringwolfAmqpExampleApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApiIntegrationTest {
public abstract class BaseApiIntegrationTest {

@Autowired
private TestRestTemplate restTemplate;
Expand All @@ -31,9 +37,12 @@ void asyncApiResourceArtifactTest() throws JSONException, IOException {
String actual = restTemplate.getForObject(url, String.class);
System.out.println("Got: " + actual);

InputStream s = this.getClass().getResourceAsStream("/asyncapi.json");
String expectedApiFileName = getExpectedApiFileName();
InputStream s = this.getClass().getResourceAsStream(expectedApiFileName);
String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8);

assertEquals(expected, actual);
}

protected abstract String getExpectedApiFileName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
"contact": {
"name": "springwolf",
"url": "https://github.com/springwolf/springwolf-core",
"email": "[email protected]"
"email": "[email protected]",
"x-phone": "+49 123 456789"
},
"license": {
"name": "Apache License 2.0"
}
"name": "Apache License 2.0",
"x-desc": "some description"
},
"x-api-audience": "company-internal"
},
"defaultContentType": "application/json",
"servers": {
Expand Down
Loading