|
| 1 | +--- |
| 2 | +sidebar_position: 69 |
| 3 | +--- |
| 4 | + |
| 5 | +import Tabs from '@theme/Tabs'; |
| 6 | +import TabItem from '@theme/TabItem'; |
| 7 | +import CodeBlock from '@theme/CodeBlock'; |
| 8 | +import CodeSchemaGroovy from '!!raw-loader!./snippets/_schema_groovy.gradle'; |
| 9 | +import CodeSchemaMaven from '!!raw-loader!./snippets/_schema_maven.xml'; |
| 10 | + |
| 11 | +# Headers |
| 12 | + |
| 13 | +Springwolf provides different ways to document headers. The `header` is mapped to an AsyncAPI `schemaObject`. |
| 14 | + |
| 15 | +## Auto-detection |
| 16 | + |
| 17 | +Besides the payload, Springwolf detects the Spring `@Header` annotation within the method signature: |
| 18 | + |
| 19 | +```java |
| 20 | +@KafkaListener(topics = "example-topic") |
| 21 | +public void receiveExamplePayload( |
| 22 | + @Payload ExamplePayloadDto payload, // @Payload is required for multiple parameters |
| 23 | + @Header(KafkaHeaders.RECEIVED_KEY) String key, |
| 24 | + @Header(KafkaHeaders.OFFSET) Integer offset) { |
| 25 | + // process |
| 26 | +} |
| 27 | +``` |
| 28 | + |
| 29 | +## Using `@AsyncOperation.Headers` |
| 30 | + |
| 31 | +Again, the annotation property `headers` of `@AsyncOperation` allows to overwrite the headers, as shown below: |
| 32 | + |
| 33 | +```java |
| 34 | +@AsyncPublisher(operation = @AsyncOperation( |
| 35 | + channelName = "example-producer-topic", |
| 36 | + headers = @AsyncOperation.Headers( // Optional |
| 37 | + schemaName = "SpringKafkaDefaultHeaders", |
| 38 | + values = { |
| 39 | + @AsyncOperation.Headers.Header( |
| 40 | + name = DEFAULT_CLASSID_FIELD_NAME, |
| 41 | + description = "Spring Type Id Header", |
| 42 | + value = "io.github.springwolf.example.dtos.ExamplePayloadDto" |
| 43 | + ), |
| 44 | + // demonstrating https://cloudevents.io |
| 45 | + @AsyncOperation.Headers.Header( |
| 46 | + name = AsyncHeadersCloudEventConstants.TYPE, |
| 47 | + description = AsyncHeadersCloudEventConstants.TYPE_DESC, |
| 48 | + value = "ExamplePayloadDto.v1") |
| 49 | + // ... |
| 50 | + } |
| 51 | + ) |
| 52 | +)) |
| 53 | +public void sendMessage(ExamplePayloadDto msg) { |
| 54 | + // process |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +## Schema |
| 59 | + |
| 60 | +Under the hood Springwolf relies on swagger-core `ModelConverters` to define the message schema. |
| 61 | + |
| 62 | +By default, the type and example values for the properties are guessed. |
| 63 | +The default Jackson `ModelResolver` supports schema definitions via `@Schema` to overwrite the property definitions. |
| 64 | + |
| 65 | +### Using `@Schema` |
| 66 | + |
| 67 | +The `@Schema` annotation allows to set many properties like `description`, `example`, `requiredMode`, `minimum` to document payloads. |
| 68 | + |
| 69 | +All properties are part of the produced AsyncAPI file. However, not all are displayed in `springwolf-ui` (see [#378](https://github.com/springwolf/springwolf-core/issues/378)) |
| 70 | + |
| 71 | +#### Usage |
| 72 | + |
| 73 | +Add the following dependency: |
| 74 | + |
| 75 | +<Tabs> |
| 76 | + <TabItem value="Groovy" label="Groovy" default> |
| 77 | + <CodeBlock language="groovy">{CodeSchemaGroovy}</CodeBlock> |
| 78 | + </TabItem> |
| 79 | + <TabItem value="Maven" label="Maven"> |
| 80 | + <CodeBlock language="xml">{CodeSchemaMaven}</CodeBlock> |
| 81 | + </TabItem> |
| 82 | +</Tabs> |
| 83 | + |
| 84 | +Then, add the `@Schema` annotation to the payload class: |
| 85 | + |
| 86 | +<!-- vale off --> |
| 87 | +```java |
| 88 | +import io.swagger.v3.oas.annotations.media.Schema; |
| 89 | +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; |
| 90 | + |
| 91 | +@Schema(description = "Example payload model") |
| 92 | +public class ExamplePayloadDto { |
| 93 | + @Schema(description = "Some string field", example = "some string value", requiredMode = REQUIRED) |
| 94 | + private String someString; |
| 95 | + |
| 96 | + public String getSomeString() { |
| 97 | + return someString; |
| 98 | + } |
| 99 | +} |
| 100 | +``` |
| 101 | +<!-- vale on --> |
| 102 | + |
| 103 | +:::note |
| 104 | +The `@AsyncMessage.description` field will always override the `@Schema` description if provided |
| 105 | +::: |
| 106 | + |
| 107 | +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/springwolf/examples/amqp/dtos/ExamplePayloadDto.java) |
| 108 | + |
| 109 | +#### Primitive, final and external classes |
| 110 | + |
| 111 | +When the `@Schema` annotation can't be attached to the payload class (that's `java.lang.String`), the payload can be wrapped in an envelope class. The actual payload is a field within this class (`StringEnvelope`), marked using `@AsyncApiPayload` and documented using the `@Schema` annotation. |
| 112 | + |
| 113 | +```java |
| 114 | +@AsyncListener( operation = @AsyncOperation( channelName = TOPIC, |
| 115 | + payloadType = StringEnvelope.class) // <- envelope class |
| 116 | +) |
| 117 | +public void receiveStringPayload(String stringPayload) { // <- The original class is used here |
| 118 | + // ... |
| 119 | +} |
| 120 | + |
| 121 | +@Data |
| 122 | +static class StringEnvelope { |
| 123 | + @AsyncApiPayload // <- The annotation marker |
| 124 | + @Schema(description = "Payload description using @Schema annotation and @AsyncApiPayload within envelope class") |
| 125 | + private final String payload; |
| 126 | +} |
| 127 | +``` |
| 128 | + |
| 129 | +:::info |
| 130 | +See [Add-Ons](../add-ons) for more information on how to document other formats |
| 131 | +::: |
0 commit comments