Skip to content

Commit

Permalink
docs: update docs for 0.17.0 release (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
timonback authored Nov 27, 2023
1 parent 2cdd1a1 commit a9f8ca6
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 162 deletions.
2 changes: 1 addition & 1 deletion docs/behind-the-scenes.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ From there, Springwolf forwards the message to the protocol specific producer.

## Plugins
`springwolf-core` provides the base functionality to orchestrate the scanning and building of the AsyncAPI document.
The different protocol (AMQP, Cloud-Stream, Kafka, SNS, SQS) are supported through plugins.
The different protocol (AMQP, Cloud-Stream, JMS, Kafka, SNS, SQS) are supported through plugins.
These plugins are found through the Spring dependency injection functionality.
When building own scanner plugins, your plugin will need to implement the `ChannelsScanner` interface.

Expand Down
10 changes: 7 additions & 3 deletions docs/configuration/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ There are 2 ways to configure Springwolf which can't be combined:

It's recommended to structure the project such that all consumers and producers (classes containing listener/producer methods) are in the same package - it's not mandatory, and if they're scattered across multiple packages, just provide the highest in hierarchy package that contains all classes.

The base package will be scanned for classes containing `@Component` annotated classes (that includes `@Service` annotated classes) for methods annotated with `@KafkaListener`, `@RabbitListener`, `@SqsListener`, `@AsyncListener`, `@AsyncPublisher`, etc.
The base package will be scanned for classes containing `@Component` annotated classes (that includes `@Service` annotated classes) for methods annotated with `@JmsListener`, `@KafkaListener`, `@RabbitListener`, `@SqsListener`, `@AsyncListener`, `@AsyncPublisher`, etc.

### `id`

Expand All @@ -47,9 +47,9 @@ The `Info` object provides metadata about the API (see [Info Object][info]).

All provided fields will be present in the generated document, but not all will be displayed in the UI.

### `Server`
### `Servers`

The `Server` object provides metadata the can help the reader understand the protocol, version, login details and more (see [Server Object][server]).
The `Server` object provides metadata to help the reader understand the protocol, version, login details and more (see [AsyncAPI Server Object][server]).

An AsyncAPI document can contain more than one server, but it's not common.

Expand All @@ -75,13 +75,17 @@ The following table contains additional properties that can be specified in the
| `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.* |
| `springwolf.endpoint.actuator.enabled` | `false` | Publish the AsyncAPI document as part of Spring Boot’s actuator feature. |
| `springwolf.use-fqn` | `false` | Use fully qualified names for the schema classes. It's recommended and **required for publishing**, but deactivated due to backwards compatibility |
| `springwolf.payload.extractable-classes..` | N/A | Extract additional payload types. See [message payloads](documenting-messages.md) for more details. |
| `springwolf.scanner.consumer-data.enabled` | `true` | Enable scanner to find consumers defined in `AsyncApiDocket`. |
| `springwolf.scanner.producer-data.enabled` | `true` | Enable scanner to find producers defined in `AsyncApiDocket`. |
| `springwolf.scanner.async-listener.enabled` | `true` | Enable scanner to find methods annotated with `@AsyncListener`. |
| `springwolf.scanner.async-publisher.enabled` | `true` | Enable scanner to find methods annotated with `@AsyncPublisher`. |
| **AMQP** | | |
| `springwolf.plugin.amqp.publishing.enabled` | `false` | Allow (anyone) to produce AMQP messages from the UI. *Note that this has security implications* |
| `springwolf.plugin.amqp.scanner.rabbit-listener.enabled` | `true` | Enable scanner to find methods annotated with `@RabbitListener`. |
| **JMS** | | |
| `springwolf.plugin.jms.publishing.enabled` | `false` | Allow (anyone) to produce JMS messages from the UI. *Note that this has security implications* |
| `springwolf.plugin.jms.scanner.jms-listener.enabled` | `true` | Enable scanner to find methods annotated with `@JmsListener`. |
| **Kafka** | | |
| `springwolf.plugin.kafka.publishing.enabled` | `false` | Allow (anyone) to produce Kafka messages from the UI. *Note that this has security implications* |
| `springwolf.plugin.kafka.publishing.producer` | `null` | Configure the Kafka producer used to publish messages from the UI. Uses identical parameters as `spring.kafka.producer` |
Expand Down
140 changes: 140 additions & 0 deletions docs/configuration/documenting-bindings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
---
sidebar_position: 66
---

# Bindings

To indicate the binding (protocol) that's documented, there are multiple options to document them.
Add at least one binding so that readers know the protocol in use and functionality like publishing works.

To use the protocol specific bindings, ensure that you have added the corresponding [plugin](../introduction/supported-protocols.md).

## Option 1: Annotations

### `@AmqpAsyncOperationBinding`

Associate this operation with AMQP, see [operation-binding] for details.

```java
@AmqpAsyncOperationBinding(cc = "example-topic-routing-key")
```

### `@KafkaAsyncOperationBinding`

Associate this operation with Kafka, see [operation-binding] for details.

```java
@KafkaAsyncOperationBinding(
bindingVersion = "1"
)
```

### `@JmsAsyncOperationBinding`

Associate this operation with JMS, see [operation-binding] for details.

```java
@JmsAsyncOperationBinding
```

### `@SnsAsyncOperationBinding`

Associate this operation with SNS, see [operation-binding] for details.
```java
@SnsAsyncOperationBinding
```

### `@SqsAsyncOperationBinding`

Associate this operation with SQS, see [operation-binding] for details.

```java
@SqsAsyncOperationBinding
```

### `@AsyncGenericOperationBinding`

This binding is generic, so that any properties can be specified.
You can define anything and there is no validation.

```java
@AsyncGenericOperationBinding(
type = "custom-binding",
fields = {
"internal-field=customValue",
"nested.key=nestedValue"
}
)
```

## Option 2: AsyncApiDocket (deprecated)

### `AmqpProducerData` / `AmqpConsumerData`

```java
AmqpProducerData exampleProducer = AmqpProducerData.amqpProducerDataBuilder()
.queueName("example-producer-channel")
.description("example-producer-channel-description")
.exchangeName("example-topic-exchange")
.routingKey("example-topic-routing-key")
.payloadType(AnotherPayloadDto.class)
.build();
```

### `KafkaProducerData` / `KafkaConsumeData`

```java
KafkaProducerData exampleProducerData = KafkaProducerData.kafkaProducerDataBuilder()
.topicName("example-producer-topic")
.description("Optional. Customer uploaded an example payload")
.payloadType(ExamplePayloadDto.class)
.headers(AsyncHeaders.NOT_USED)
.build();
```

## Binding properties
Explanation of the different binding properties.

### General
The following properties are the same for all bindings.

#### Queue Name (Channel Name)

The queue name that will be used to publish messages to by the UI.

#### Description

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.

#### Payload Type

The class object of the payload that will be published to this channel.

#### Headers

The Kafka headers describing the metadata of the payload, more details in the generic ProducerData.

The Springwolf comes with a special `AsyncHeadersCloudEventConstants` to document CloudEvents.

The `kafka` header `__TypeId__` (constant from ` AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME`) can be documented as well.

### AMQP

#### Exchange Name

The exchange name that will be used to bind queues to.

#### Routing Key

The routing key used when publishing a message.


### Kafka

#### Group Id
The group id that will be used during message consumption

#### Client Id
The client id to identify the consumer

[operation-binding]: https://www.asyncapi.com/docs/reference/specification/v2.6.0#operationBindingsObject
92 changes: 14 additions & 78 deletions docs/configuration/documenting-consumers.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ For these use-cases, Springwolf provides additional ways to explicitly add them
To document consumers, either:
- add the `@AsyncListener` annotation or
- (deprecated) declare the `ConsumerData` object as part of the `AsyncApiDocket` or
- rely on the auto-detection of `@KafkaListener`, `@RabbitListener`, `@SqsListener`
- rely on the auto-detection of `@JmsListener`, `@KafkaListener`, `@RabbitListener`, `@SqsListener`

You are free to use all options together. Per channel and operation, first `ConsumerData` is used, then `@AsyncListener` and last the auto-detected annotations.

Expand All @@ -29,6 +29,7 @@ Below is an example to demonstrate the annotation:
@AsyncListener(operation = @AsyncOperation(
channelName = "example-consumer-topic",
description = "Optional. Customer uploaded an example payload",
servers = {"kafka"},
headers = @AsyncOperation.Headers(
schemaName = "SpringKafkaDefaultHeaders",
values = {
Expand All @@ -37,6 +38,12 @@ Below is an example to demonstrate the annotation:
description = "Spring Type Id Header",
value = "io.github.stavshamir.springwolf.example.dtos.ExamplePayloadDto"
),
// (demonstrating https://cloudevents.io)
@AsyncOperation.Headers.Header(
name = AsyncHeadersCloudEventConstants.TYPE,
description = AsyncHeadersCloudEventConstants.TYPE_DESC,
value = "NestedPayloadDto.v1")
// ...
}
)
))
Expand All @@ -58,34 +65,14 @@ The channel name (or topic name in case of Kafka) - this is the name that will b

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.

### Payload Type

The class object of the payload that will be consumed from this channel.
If not specified, it's extracted from the method arguments.

### Header

Optional. The headers describing the metadata of the payload.

### `@AmqpAsyncOperationBinding`

Associate this operation with AMQP, see [operation-binding] for details.
### Servers

```java
@AmqpAsyncOperationBinding(cc = "example-topic-routing-key")
```

### `@KafkaAsyncOperationBinding`

Associate this operation with Kafka, see [operation-binding] for details.

```java
@KafkaAsyncOperationBinding(
bindingVersion = "1",
clientId = "foo-clientId",
groupId = "#{'foo-groupId'}"
)
```
Optional. Useful when an application is connect to multiple brokers and wants to indicate to which broker the channel belongs to.
The server needs to exist in [configuration > Servers](configuration.md) as well.


## Option 2: `ConsumerData` (deprecated)
Expand Down Expand Up @@ -133,7 +120,7 @@ Optional. The description allows for human-friendly text to verbosely explain th

### Binding

This property is used to discriminate the producer's protocol and provide protocol-specific properties (see [operation-binding])).
This property is used to discriminate the producer's protocol and provide protocol-specific properties (see [documenting bindings](documenting-bindings.md)).

### Payload Type

Expand Down Expand Up @@ -172,58 +159,7 @@ The above Kafka `ConsumerData` simplifies to the following `KafkaConsumerData`:
```


## Option 3: `@KafkaListener`, `@RabbitListener`, `@SqsListener`
The `@KafkaListener`, `@RabbitListener`, `@SqsListener` annotations are detected automatically.
## Option 3: `@JmsListener`, `@KafkaListener`, `@RabbitListener`, `@SqsListener`
The `@JmsListener`, `@KafkaListener`, `@RabbitListener`, `@SqsListener` annotations are detected automatically.
There is nothing more to do.
Use the other options if the provided documentation is insufficient.


## AMQP Parameters
### Queue Name (Channel Name)

The queue name that will be used to consume messages from.

### Description

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.

### Exchange Name

The exchange name that will be used to bind queues to.

### Routing Key

The routing key used when publishing a message.

### Payload Type

The class object of the payload that will be consumed from this channel.


## Kafka Parameters

### Topic Name (Channel Name)

The topic name that will be used to consume messages from.

### Description

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.

### Payload Type

The class object of the payload that will be consumed from this channel.

### Headers

The Kafka headers describing the metadata of the payload, more details in the generic ConsumerData.

The Springwolf Kafka plugin comes with a special `AsyncHeadersForSpringKafkaBuilder` to document the `__TypeId__` header of the `spring-kafka` dependency.

## Examples

- [AMQP Example](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/AsyncApiConfiguration.java)
- [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/cloudstream/configuration/AsyncApiConfiguration.java)
- [Kafka Example](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/configuration/AsyncApiConfiguration.java)

[operation-binding]: https://www.asyncapi.com/docs/reference/specification/v2.0.0#operationBindingsObject
36 changes: 35 additions & 1 deletion docs/configuration/documenting-messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ For example:
@AsyncPublisher(operation = @AsyncOperation(
channelName = "example-producer-topic",
description = "Optional. Customer uploaded an example payload",
payloadType = ExamplePayloadDto.class, // optional
message = @AsyncMessage(
messageId = "my-unique-id",
name = "ExamplePayloadDto",
Expand All @@ -33,14 +34,43 @@ public void sendMessage(ExamplePayloadDto msg) {
}
```

## Payload Type

Springwolf tries to auto-detect the payload type based on the method signature.

When the method has multiple arguments, the payload can be indicated via `@Payload`, i.e.
```java
public void sendMessage(@Payload ExamplePayloadDto msg, String traceId, Object loggingContext) {}
```

Alternatively, the annotation property `payloadType` of `@AsyncOperation` allows to overwrite the detected class.

### Unwrapping the Payload

Sometimes, the payload type is wrapped in other objects.
Some wrappers are automatically unwrapped, including `Message<String>`, which becomes `String`.

:::note
The [configuration property](configuration.md) to modify the defaults is currently in _beta_.
:::

Assuming a method signature of `sendMessage(Function<Void, String> msg)`, where the actual payload is located in parameter index 1 (String).
Adding the configuration property `springwolf.payload.extractable-classes.java.util.function.Function=1` tells Springwolf how to handle this payload type.

The configuration property is split into three parts.
First, the base property `springwolf.payload.extractable-classes`.
Second, the canonical class name, `java.util.function.Function` in this case.
And third, the generic parameter index (`1`).


## Schema

Under the hood Springwolf relies on swagger-core `ModelConverters` to define the message schema.

By default, the type and example values for the properties are guessed.
The default Jackson `ModelResolver` supports schema definitions via `@Schema` to overwrite the property definitions.

## Using `@Schema`
### Using `@Schema`

The `@Schema` annotation allows to set many properties like `description`, `example`, `requiredMode` to document payloads.

Expand Down Expand Up @@ -84,6 +114,10 @@ The `@AsyncMessage.description` field will always override the `@Schema` descrip

For a full example, take a look at [ExamplePayloadDto.java in `springwolf-amqp-example`](https://github.com/springwolf/springwolf-core/blob/master/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/dtos/ExamplePayloadDto.java)

### `json-schema`

The [`springwolf-add-ons/springwolf-json-schema`](https://github.com/springwolf/springwolf-core/tree/master/springwolf-add-ons/springwolf-json-schema) adds the [json-schema](https://json-schema.org) schema to the AsyncApi document.

## Custom ModelConverters

Additionally, custom `ModelConverters` are supported.
Expand Down
Loading

0 comments on commit a9f8ca6

Please sign in to comment.