Skip to content

Commit 3a1695f

Browse files
authored
Add documentation for @AsyncListener, @AsyncPublisher, application.properties
2 parents 93daea2 + e66a4d9 commit 3a1695f

10 files changed

+486
-232
lines changed

docs/configuration.md

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
---
22
sidebar_position: 3
33
---
4+
import Tabs from '@theme/Tabs';
5+
import TabItem from '@theme/TabItem';
6+
import CodeBlock from '@theme/CodeBlock';
7+
import CodeConfigurationProperties from '!!raw-loader!./snippets/_configuration_properties.md';
8+
import CodeConfigurationAsyncApiDocket from '!!raw-loader!./snippets/_configuration_asyncApiDocket.md';
49

510
# Configuration
611

7-
## Configuration Class
12+
## Activating
813

914
- You need to provide a configuration class annotated with:
1015
1. `@Configuration`
@@ -14,31 +19,32 @@ sidebar_position: 3
1419
```java
1520
@Configuration
1621
@EnableAsyncApi
17-
public class AsyncApiConfiguration {
18-
...
19-
}
22+
public class AsyncApiConfiguration { }
2023
```
2124

22-
## AsyncApiDocket
25+
## Springwolf configuration
2326

24-
You need to provide an `AsyncApiDocket` bean, which provides Springwolf with metadata that is either not specified in code or can't be picked up automatically.
27+
There are 2 ways to configure springwolf:
2528

26-
```java
27-
@Bean
28-
public AsyncApiDocket asyncApiDocket() {
29-
return AsyncApiDocket.builder()
30-
.basePackage(...)
31-
.info(...)
32-
.server(...)
33-
.build();
34-
}
35-
```
29+
1. `application.properties`, which is simple and should suit most use-cases
30+
2. `AsyncApiDocket`, which allows adding producers and consumers via code (and avoiding annotations)
31+
32+
<Tabs>
33+
<TabItem value="application.properties" label="application.properties" default>
34+
Add the following to the spring application.properties file.
35+
<CodeBlock language="properties">{CodeConfigurationProperties}</CodeBlock>
36+
</TabItem>
37+
<TabItem value="AsyncApiDocket" label="AsyncApiDocket">
38+
Add a AsyncApiDocket bean to the spring context, for example as part of the AsyncApiConfiguration.
39+
<CodeBlock language="java">{CodeConfigurationAsyncApiDocket}</CodeBlock>
40+
</TabItem>
41+
</Tabs>
3642

3743
### basePackage (required)
3844

39-
It is recommended to structue the project such that all consumers (classes containing listener methods) are in the same package - it is not mandatory, and if the consumer are scattered across multiple packages, just provide the highest in hierarchy package that containes all of them.
45+
It is recommended to structure the project such that all consumers and producers (classes containing listener/producer methods) are in the same package - it is not mandatory, and if they are scattered across multiple packages, just provide the highest in hierarchy package that contains all of them.
4046

41-
The base package will be scanned for classes containing `@Component` annotated classes (that includes `@Service` annotated classes) for methods annotated with `@KafkaListener`, `@RabbitListener`, etc.
47+
The base package will be scanned for classes containing `@Component` annotated classes (that includes `@Service` annotated classes) for methods annotated with `@KafkaListener`, `@RabbitListener`, `@AsyncListener`, `@AsyncPublisher`, etc.
4248

4349
### Info (required)
4450

@@ -52,33 +58,18 @@ The `Server` object provides metadata the can help the reader understand the pro
5258

5359
An AsyncAPI document can contain more than one server, but it is not common.
5460

55-
The server is provided to the document with an arbitrary name as the key, and a `Server` object as the value:
56-
57-
```java
58-
@Bean
59-
public AsyncApiDocket asyncApiDocket() {
60-
Server kafkaServer = Server.builder()
61-
.protocol("kafka")
62-
.url(BOOTSTRAP_SERVERS)
63-
.build();
64-
65-
return AsyncApiDocket.builder()
66-
.basePackage(...)
67-
.info(...)
68-
.server("whatever name you want", kafkaServer)
69-
.build();
70-
}
71-
```
72-
7361
As with the `Info` object, all provided fields will be present in the generated document, but not all will be displayed in the UI.
7462

75-
## application.properties
63+
## Additional `application.properties`
7664

77-
The following table contains the complete list of additional properties that can be specified in the `application.properties` file:
65+
The following table contains additional properties that can be specified in the `application.properties` file:
7866

79-
| Property Name | Default Value | Description |
80-
| ------------- | ------------- | ----------- |
81-
| `springwolf.paths.docs` | `/springwolf/docs` | The path of the AsyncAPI document in JSON format. *Note that at the moment the UI will work only with the default value.* |
67+
| Property Name | Default Value | Description |
68+
|----------------------------------------------| ------------- |---------------------------------------------------------------------------------------------------------------------------|
69+
| `springwolf.enabled` | `true` | Allows to enable/disable springwolf at one central place. |
70+
| `springwolf.paths.docs` | `/springwolf/docs` | The path of the AsyncAPI document in JSON format. *Note that at the moment the UI will work only with the default value.* |
71+
| `springwolf.plugin.amqp.publishing.enabled` | `false` | Allow (anyone) to produce amqp messages from the UI. *Note that this has security implications* |
72+
| `springwolf.plugin.kafka.publishing.enabled` | `false` | Allow (anyone) to produce kafka messages from the UI. *Note that this has security implications* |
8273

83-
[info]: https://www.asyncapi.com/docs/specifications/v2.0.0#infoObject).
84-
[server]: https://www.asyncapi.com/docs/specifications/v2.0.0#serverObject
74+
[info]: https://www.asyncapi.com/docs/reference/specification/v2.0.0#infoObject.
75+
[server]: https://www.asyncapi.com/docs/reference/specification/v2.0.0#serversObject

docs/documenting-consumers.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
---
2+
sidebar_position: 5
3+
---
4+
5+
# Documenting Consumers
6+
7+
Springwolf comes with build-in support to auto-detect listeners of supported protocols.
8+
9+
Sometimes projects are configured in a way that makes Springwolf unable to automatically locate consumers or the generated documentation is insufficient.
10+
For these use-cases, Springwolf provides additional ways to explicitly add them to the generated document.
11+
12+
To document consumers, either:
13+
- add the `@AsyncListener` annotation or
14+
- declare the `ConsumerData` object as part of the `AsyncApiDocket` or
15+
- rely on the auto-detection of `@KafkaListener`, `@RabbitListener`
16+
17+
You are free to use all options together. Per channel and operation, first `ConsumerData` is used, then `@AsyncListener` and last the auto-detected annotations.
18+
19+
## Option 1: `@AsyncListener`
20+
21+
The `@AsyncListener` annotation is added to the method of the listeners and extracts the payload from its arguments.
22+
Additional fields can be documented.
23+
24+
The protocol operation binding is configured via `@AmqpAsyncOperationBinding` or `@KafkaAsyncOperationBinding`, which has to be on the same method.
25+
26+
Below is an example to demonstrate the annotation:
27+
```java
28+
@KafkaListener
29+
@AsyncListener(operation = @AsyncOperation(
30+
channelName = "example-consumer-topic",
31+
description = "Optional. Customer uploaded an example payload",
32+
headers = @AsyncOperation.Headers(
33+
schemaName = "SpringKafkaDefaultHeaders",
34+
values = {
35+
@AsyncOperation.Headers.Header(
36+
name = DEFAULT_CLASSID_FIELD_NAME,
37+
description = "Spring Type Id Header",
38+
value = "io.github.stavshamir.springwolf.example.dtos.ExamplePayloadDto"
39+
),
40+
}
41+
)
42+
))
43+
@KafkaAsyncOperationBinding
44+
public void receiveMessage(ExamplePayloadDto msg) {
45+
// process
46+
}
47+
```
48+
49+
:::note
50+
Springwolf only finds methods that are within the `base-package`.
51+
:::
52+
53+
### Channel Name
54+
55+
The channel name (or topic name in case of Kafka) - this is the name that will be used to subscribe to messages to by the UI.
56+
57+
### Description
58+
59+
Optional. The description allows for human-friendly text to verbosely explain the _message_, like specific domain, what the topic is used for and which data it contains.
60+
61+
### Payload Type
62+
63+
The class object of the payload that will be consumed from this channel.
64+
If not specified, it is extracted from the method arguments.
65+
66+
### Header
67+
68+
Optional. The headers describing the metadata of the payload.
69+
70+
### `@AmqpAsyncOperationBinding`
71+
72+
Associate this operation with amqp, see [operation-binding] for details.
73+
74+
```java
75+
@AmqpAsyncOperationBinding(cc = "example-topic-routing-key")
76+
```
77+
78+
### `@KafkaAsyncOperationBinding`
79+
80+
Associate this operation with kafka, see [operation-binding] for details.
81+
82+
```java
83+
@KafkaAsyncOperationBinding(
84+
bindingVersion = "1",
85+
clientId = "foo-clientId",
86+
groupId = "#{'foo-groupId'}"
87+
)
88+
```
89+
90+
91+
## Option 2: `ConsumerData`
92+
93+
:::tip
94+
Use specific ConsumerData types `AmqpConsumerData` & `KafkaConsumerData` for protocol specific attributes
95+
:::
96+
97+
Below is an example of describing a Kafka consumer:
98+
99+
```java
100+
@Bean
101+
public AsyncApiDocket asyncApiDocket() {
102+
103+
ConsumerData exampleConsumerData = ConsumerData.builder()
104+
.channelName("example-consumer-topic")
105+
.description("Optional. Customer uploaded an example payload")
106+
.operationBinding(ImmutableMap.of("kafka", new KafkaOperationBinding()))
107+
.payloadType(ExamplePayloadDto.class)
108+
.headers(AsyncHeaders.NOT_USED)
109+
.build();
110+
111+
return AsyncApiDocket.builder()
112+
.basePackage(...)
113+
.info(...)
114+
.server(...)
115+
.consumer(exampleConsumerData)
116+
.build();
117+
}
118+
```
119+
120+
Multiple consumers can be configured by calling the `consumer()` method multiple times.
121+
122+
### Channel Name
123+
124+
The channel name (or topic name in case of Kafka) - this is the name that will be used to subscribe to messages to by the UI.
125+
126+
### Description
127+
128+
Optional. The description allows for human-friendly text to verbosely explain the _message_, like specific domain, what the topic is used for and which data it contains.
129+
130+
### Binding
131+
132+
This property is used to discriminate the producer's protocol and provide protocol-specific properties (see [operation-binding])).
133+
134+
### Payload Type
135+
136+
The class object of the payload that will be consumed from this channel.
137+
138+
### Header
139+
140+
Optional. The headers describing the metadata of the payload.
141+
By default, `AsyncHeaders.NOT_DOCUMENTED` is used to indicate that no explicit header documentation exists.
142+
Use `AsyncHeaders` to add your custom headers, use `AsyncHeaders.NOT_USED` if you do not use headers and `AsyncHeadersForCloudEventsBuilder` if your events follow the CloudEvent specification.
143+
144+
145+
### `AmqpConsumerData`
146+
147+
The above Kafka `ConsumerData` equivalent in `AmqpConsumerData`:
148+
```java
149+
AmqpConsumerData exampleConsumer = AmqpConsumerData.amqpConsumerDataBuilder()
150+
.queueName("example-consumer-channel")
151+
.description("example-consumer-channel-description")
152+
.exchangeName("example-topic-exchange")
153+
.routingKey("example-topic-routing-key")
154+
.payloadType(AnotherPayloadDto.class)
155+
.build();
156+
```
157+
158+
### `KafkaConsumerData`
159+
160+
The above Kafka `ConsumerData` simplifies to the following `KafkaConsumerData`:
161+
```java
162+
KafkaConsumerData exampleConsumerData = KafkaConsumerData.kafkaConsumerDataBuilder()
163+
.topicName("example-consumer-topic")
164+
.description("Optional. Customer uploaded an example payload")
165+
.payloadType(ExamplePayloadDto.class)
166+
.headers(AsyncHeaders.NOT_USED)
167+
.build();
168+
```
169+
170+
171+
## Option 3: `@KafkaListener`, `@RabbitListener`
172+
The `@KafkaListener` and `@RabbitListener` annotations are detected automatically.
173+
There is nothing more to do.
174+
Use the other options if the provided documentation is insufficient.
175+
176+
177+
## AMQP Parameters
178+
### Queue Name (Channel Name)
179+
180+
The queue name that will be used to consume messages from.
181+
182+
### Description
183+
184+
Optional. The description allows for human-friendly text to verbosely explain the _message_, like specific domain, what the topic is used for and which data it contains.
185+
186+
### Exchange Name
187+
188+
The exchange name that will be used to bind queues to.
189+
190+
### Routing Key
191+
192+
The routing key used when publishing a message.
193+
194+
### Payload Type
195+
196+
The class object of the payload that will be consumed from this channel.
197+
198+
199+
## Kafka Parameters
200+
201+
### Topic Name (Channel Name)
202+
203+
The topic name that will be used to consume messages from.
204+
205+
### Description
206+
207+
Optional. The description allows for human-friendly text to verbosely explain the _message_, like specific domain, what the topic is used for and which data it contains.
208+
209+
### Payload Type
210+
211+
The class object of the payload that will be consumed from this channel.
212+
213+
### Headers
214+
215+
The Kafka headers describing the metadata of the payload, more details in the generic ConsumerData.
216+
217+
The Springwolf Kafka plugin comes with a special `AsyncHeadersForSpringKafkaBuilder` to document the `__TypeId__` header of the spring-kafka dependency.
218+
219+
## Examples
220+
221+
- [AMQP Example](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/configuration/AsyncApiConfiguration.java)
222+
- [Cloud Stream Example](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/stavshamir/springwolf/example/configuration/AsyncApiConfiguration.java)
223+
- [Kafka Example](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/configuration/AsyncApiConfiguration.java)
224+
225+
[operation-binding]: https://www.asyncapi.com/docs/reference/specification/v2.0.0#operationBindingsObject

0 commit comments

Comments
 (0)