Skip to content

docs: release 1.12.0 #104

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 4 commits into from
Mar 28, 2025
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
2 changes: 1 addition & 1 deletion docs/configuration/documenting-bindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ You can define anything and there is no validation.
```

:::info
See [Add-Ons / Generic Annotation Binding](../add-ons#generic-binding) for more information
See [Add-Ons / Generic Annotation Binding](../introduction/add-ons.mdx#generic-binding) for more information
:::

## Binding properties
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/documenting-messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,5 @@ static class StringEnvelope {
```

:::info
See [Add-Ons](../add-ons) for more information on how to document other formats
See [Add-Ons](../introduction/add-ons) for more information on how to document other formats
:::
105 changes: 34 additions & 71 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,9 @@ Either create a custom spring controller to serve the file or [serve static reso

Note: `springwolf-ui` doesn't support the full AsyncAPI spec.

### Unit test verification
### Springwolf in unit / integration test

With the AsyncAPI artifact checked into the repository at `src/test/resources/asyncapi.json`,
a unit test can verify that the current code still matches the expected AsyncAPI specification.
Additionally, a diff reveals (un)expected changes.

Example unit test:

```java
@SpringBootTest(
classes = {SpringwolfKafkaExampleApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApiIntegrationTest {

@Autowired
private TestRestTemplate restTemplate;

@Test
void asyncApiResourceArtifactTest() throws IOException {
String url = "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);

// writing the actual file can be useful for debugging (remember: gitignore)
Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual);

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

assertEquals(expected, actual);
}
}
```

For a full example, check the [springwolf-kafka-example ApiIntegrationTest](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java)
See [Static Generation](static-generation.md).

## Troubleshooting

Expand Down Expand Up @@ -100,18 +69,23 @@ Be sure to enable fully qualified names ([`use-fqn`](configuration/configuration

Spring Security allows to limit access to authorized users.

### Consumers are detected multiple times (with different payloads)

When Springwolf finds multiple consumers/producers for the same channel/topic, these are merged together.
This is expected, as there are use-cases where different payloads are sent via the same channel/topic.
### Classes have fully qualified names (`io.springwolf.package.ClassName`)

Springwolf uses on scanners to find all consumer and producers in your application.
Most likely two scanners found your consumer/producer each.
See [configuration](configuration/configuration.mdx) to disable scanners.
Disable the [fully qualified class name (FQN) option (`springwolf.use-fqn=false`)](configuration/configuration.mdx).

### Only one of multiple classes with the same name (different package) is detected

Enable the fully qualified class name (FQN) option (`springwolf.use-fqn=true`) so that Springwolf uses the FQN internally.
Enable the [fully qualified class name (FQN) option (`springwolf.use-fqn=true`)](configuration/configuration.mdx).

### Springwolf interferes with OpenAPI documentation

Springwolf uses `swagger-core` to analyze classes, which is used by some OpenAPI libraries like `springdoc-openapi`.
`swagger-core` configuration is partly global and can't be isolated.

Options:

1. Use the same settings in Springwolf and the other library (including the [fully qualified class name (FQN) option](configuration/configuration.mdx)).
2. Don't run Springwolf and the other library at the same time, for example by [generating the documentation at build time](static-generation.md).

### Generic types (List) don't contain item properties

Expand All @@ -133,6 +107,25 @@ class ListWrapper extends ArrayList<String> {}
public void sendMessage(ListWrapper<String> msg) {}
```

### Consumers are detected multiple times (with different payloads)

When Springwolf finds multiple consumers/producers for the same channel/topic, these are merged together.
This is expected, as there are use-cases where different payloads are sent via the same channel/topic.

Springwolf uses on scanners to find all consumer and producers in your application.
Most likely two scanners found your consumer/producer each.
See [configuration](configuration/configuration.mdx) to disable scanners.

## Usage Patterns

### How to access the generated documentation within java

Use the `AsyncApiService` to access the generated documentation.

### How to customize the generated documentation

See the [customization page](configuration/customizing.md)

## Release Notes / Migration Guide / Updating / Upgrading

Releases are managed in [GitHub Releases](https://github.com/springwolf/springwolf-core/releases),
Expand Down Expand Up @@ -160,33 +153,3 @@ Last versions to support Spring Boot 2.X:
- `springwolf-core:0.6.0`
- `springwolf-kafka:0.10.0`
- `springwolf-ui:0.6.0`

## Usage Patterns

### How to access the generated documentation within java

Use the `AsyncApiService` to access the generated documentation.

### How to generate the documentation at build time

#### With Gradle

You can use the [`springdoc-openapi-gradle-plugin`](https://github.com/springdoc/springdoc-openapi-gradle-plugin) and configure the plugin
for Springwolf by pointing it to the Springwolf docs endpoint:

```groovy
openApi {
apiDocsUrl = "http://localhost:8080/springwolf/docs"
outputDir = file("$buildDir/docs")
outputFileName = "async-api.json"
}
```

The [`springwolf-kafka-example`](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/build.gradle)
contains a working example.

The plugin will startup the spring boot application by using the `bootRun` task and then try to download the documentation
from the given `apiDocsUrl` and store it in the `outputDir` and with the given `outputFileName`.

If your application is unable to start up with the `bootRun` task, see if [customBootRun](https://github.com/springdoc/springdoc-openapi-gradle-plugin#customization)
properties can help you.
4 changes: 2 additions & 2 deletions docs/add-ons.mdx → docs/introduction/add-ons.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 50
sidebar_position: 20
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Expand Down Expand Up @@ -49,7 +49,7 @@ Adding a model converter is demoed in [`springwolf-add-ons/springwolf-common-mod
</Tabs>
Latest version: ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-json-schema?color=green&label=springwolf&style=plastic)

Specific bindings are provided for the different [supported protocols](introduction/supported-protocols) but if you need
Specific bindings are provided for the different [supported protocols](supported-protocols) but if you need
to document a protocol that's not support yet, you can use this generic binding and specify any property you need.

### `@AsyncGenericOperationBinding`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
dependencies {
implementation 'io.github.springwolf:springwolf-common-model-converters:1.11.0'
implementation 'io.github.springwolf:springwolf-common-model-converters:1.12.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-common-model-converters</artifactId>
<version>1.11.0</version>
<version>1.12.0</version>
</dependency>
</dependencies>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
dependencies {
implementation 'io.github.springwolf:springwolf-generic-binding:1.11.0'
implementation 'io.github.springwolf:springwolf-generic-binding:1.12.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-generic-binding</artifactId>
<version>1.11.0</version>
<version>1.12.0</version>
</dependency>
</dependencies>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
dependencies {
implementation 'io.github.springwolf:springwolf-json-schema:1.11.0'
implementation 'io.github.springwolf:springwolf-json-schema:1.12.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-json-schema</artifactId>
<version>1.11.0</version>
<version>1.12.0</version>
</dependency>
</dependencies>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
dependencies {
implementation 'io.github.springwolf:springwolf-kotlinx-serialization-model-converter:1.11.0'
implementation 'io.github.springwolf:springwolf-kotlinx-serialization-model-converter:1.12.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-kotlinx-serialization-model-converter</artifactId>
<version>1.11.0</version>
<version>1.12.0</version>
</dependency>
</dependencies>
4 changes: 2 additions & 2 deletions docs/introduction/supported-protocols.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ The supported binding annotations are:
| STOMP (WebSocket) | `@StompAsyncOperationBinding` | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-stomp-binding?color=green&label=springwolf-stomp-binding&style=plastic) |

:::info
See [Add-Ons / Generic Annotation Binding](../add-ons#generic-binding)
See [Add-Ons / Generic Annotation Binding](add-ons.mdx#generic-binding)
:::

## Wire format (Data serialization)
Expand All @@ -64,7 +64,7 @@ Besides the classical JSON events, Springwolf has best-effort support for some o
[Protobuf](https://protobuf.dev) is demoed in [kafka example](#native-support).

To remove the fields generated by the Protobuf class generated, add a `ModelResolver` bean, which uses the `ProtobufModule` to your project.
See [ObjectMapperConfiguration](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/configuration/ObjectMapperConfiguration.java) for details.
See [ProtobufConfiguration](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/configuration/ProtobufConfiguration.java) for details.

[amqp]:https://github.com/springwolf/springwolf-core/tree/master/springwolf-examples/springwolf-amqp-example
[cloud-stream]:https://github.com/springwolf/springwolf-core/tree/master/springwolf-examples/springwolf-cloud-stream-example
Expand Down
4 changes: 2 additions & 2 deletions docs/snippets/_springwolf_groovy.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dependencies {
// Provides the documentation API
implementation 'io.github.springwolf:springwolf-kafka:1.11.0'
implementation 'io.github.springwolf:springwolf-kafka:1.12.0'

// Provides the UI - optional (recommended)
runtimeOnly 'io.github.springwolf:springwolf-ui:1.11.0'
runtimeOnly 'io.github.springwolf:springwolf-ui:1.12.0'
}
4 changes: 2 additions & 2 deletions docs/snippets/_springwolf_maven.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-kafka</artifactId>
<version>1.11.0</version>
<version>1.12.0</version>
</dependency>
<!-- Provides the UI - optional (recommended) -->
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-ui</artifactId>
<version>1.11.0</version>
<version>1.12.0</version>
</dependency>
</dependencies>
100 changes: 100 additions & 0 deletions docs/static-generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
sidebar_position: 40
---

# Static Generation

Users tend to start out with running Springwolf at runtime as part of the Spring Boot application context.
Still, it's possible to generate the AsyncAPI documentation statically at build time.

One use-case is to protect against unexpected API changes using a test.
For this, the expected `asyncapi.json` file is stored in the VCS repository.

## Spring Boot Test (full spring context)

The most simple way is a Spring Boot test (taken from [springwolf-kafka-example](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java)):

```java
@SpringBootTest(
classes = {SpringwolfKafkaExampleApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApiIntegrationTest {

@Autowired
private TestRestTemplate restTemplate;

@Test
void asyncApiResourceArtifactTest() throws IOException {
// given
String url = "/springwolf/docs";

// when
String actual = restTemplate.getForObject(url, String.class);

// then
// writing the actual file can be useful for debugging (remember: .gitignore)
Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual);

// then
InputStream s = this.getClass().getResourceAsStream("/asyncapi.json");
String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim();
assertEquals(expected, actual);
}
}
```

## Springwolf Standalone (minimal spring context)

Especially for large application, starting the full Spring Boot context can be slow.
Springwolf _standalone_ uses a minimal Spring application context, by only including beans and configurations marked with `@StandaloneConfiguration`.

Demo code (taken from [`springwolf-kafka-example`](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/StandaloneTest.java)):

```java
class StandaloneTest {

@Test
public void asyncApiStandaloneArtifactTest() throws IOException {
// given
StandaloneApplication standaloneApplication =
DefaultStandaloneApplication.builder().buildAndStart();

// when
AsyncAPI asyncApi = standaloneApplication.getAsyncApiService().getAsyncAPI();
String actual = new DefaultAsyncApiSerializerService().toJsonString(asyncApi);

// then
// writing the actual file can be useful for debugging (remember: gitignore)
Files.writeString(Path.of("src", "test", "resources", "asyncapi.standalone.json"), actual);

// then
InputStream s = this.getClass().getResourceAsStream("/asyncapi.json");
String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim();
assertEquals(expected, actualPatched);
}
}
```

By default, only the `io.github.springwolf` package is scanned and `@StandaloneConfiguration` in other packages are _not_ picked up.
Use the `DefaultStandaloneApplication.builder()` to customize the Spring environment, load custom beans and configurations.

The [`application.properties` configuration](configuration/configuration.mdx) is picked up.

## Gradle Plugin (full spring context)

You can use the [`springdoc-openapi-gradle-plugin`](https://github.com/springdoc/springdoc-openapi-gradle-plugin) and configure the plugin
for Springwolf (taken from [`springwolf-kafka-example`](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/build.gradle)):

```groovy
openApi {
apiDocsUrl = "http://localhost:8080/springwolf/docs"
outputDir = file("$buildDir/docs")
outputFileName = "asyncapi.json"
}
```

The plugin will start up the spring boot application by using the `bootRun` task and then try to download the documentation
from the given `apiDocsUrl` and store it in the `outputDir` and with the given `outputFileName`.

If your application is unable to start up with the `bootRun` task, see if [customBootRun](https://github.com/springdoc/springdoc-openapi-gradle-plugin#customization)
properties can help you.
Loading