Skip to main content

Headers

Springwolf provides different ways to document headers. The header is mapped to an AsyncAPI schemaObject.

Auto-detection

Besides the payload, Springwolf detects the Spring @Header annotation within the method signature:

@KafkaListener(topics = "example-topic")
public void receiveExamplePayload(
@Payload ExamplePayloadDto payload, // @Payload is required for multiple parameters
@Header(KafkaHeaders.RECEIVED_KEY) String key,
@Header(KafkaHeaders.OFFSET) Integer offset) {
// process
}

Using @AsyncOperation.Headers

Again, the annotation property headers of @AsyncOperation allows to overwrite the headers, as shown below:

@AsyncPublisher(operation = @AsyncOperation(
channelName = "example-producer-topic",
headers = @AsyncOperation.Headers( // Optional
schemaName = "SpringKafkaDefaultHeaders",
values = {
@AsyncOperation.Headers.Header(
name = DEFAULT_CLASSID_FIELD_NAME,
description = "Spring Type Id Header",
value = "io.github.springwolf.example.dtos.ExamplePayloadDto"
),
// demonstrating https://cloudevents.io
@AsyncOperation.Headers.Header(
name = AsyncHeadersCloudEventConstants.TYPE,
description = AsyncHeadersCloudEventConstants.TYPE_DESC,
value = "ExamplePayloadDto.v1")
// ...
}
)
))
public void sendMessage(ExamplePayloadDto msg) {
// process
}

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

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

All properties are part of the produced AsyncAPI file. However, not all are displayed in springwolf-ui (see #378)

Usage

Add the following dependency:

dependencies {
implementation 'io.swagger.core.v3:swagger-core:2.2.22'
}

Then, add the @Schema annotation to the payload class:

import io.swagger.v3.oas.annotations.media.Schema;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

@Schema(description = "Example payload model")
public class ExamplePayloadDto {
@Schema(description = "Some string field", example = "some string value", requiredMode = REQUIRED)
private String someString;

public String getSomeString() {
return someString;
}
}
note

The @AsyncMessage.description field will always override the @Schema description if provided

For a full example, take a look at ExamplePayloadDto.java in springwolf-amqp-example

Primitive, final and external classes

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.

@AsyncListener( operation = @AsyncOperation( channelName = TOPIC,
payloadType = StringEnvelope.class) // <- envelope class
)
public void receiveStringPayload(String stringPayload) { // <- The original class is used here
// ...
}

@Data
static class StringEnvelope {
@AsyncApiPayload // <- The annotation marker
@Schema(description = "Payload description using @Schema annotation and @AsyncApiPayload within envelope class")
private final String payload;
}
info

See Add-Ons for more information on how to document other formats