From c8d333d9ff42bb36dea92d56f098d33d803b159e Mon Sep 17 00:00:00 2001 From: Timon Back Date: Fri, 3 Nov 2023 14:42:51 +0100 Subject: [PATCH] feat(kafka): demonstrate cloud event headers in example (#426) * feat(kafka): demonstrate cloud event headers in example * feat(kafka): rename schema to SpringDefaultHeaderAndCloudEvent --- .../annotation/AsyncOperation.java | 2 +- .../AsyncHeadersCloudEventConstants.java | 19 +++++ .../AsyncHeadersForCloudEventsBuilder.java | 42 ++++++++--- .../kafka/producers/NestedProducer.java | 32 ++++++++- .../src/test/resources/asyncapi.json | 69 ++++++++++++++++++- 5 files changed, 151 insertions(+), 13 deletions(-) create mode 100644 springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersCloudEventConstants.java diff --git a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncOperation.java b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncOperation.java index 60f2595bd..8b8c52662 100644 --- a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncOperation.java +++ b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncOperation.java @@ -59,7 +59,7 @@ String name(); /** - * Mapped to {@link AsyncHeaderSchema#getDescription()} ()} + * Mapped to {@link AsyncHeaderSchema#getDescription()} */ String description() default ""; diff --git a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersCloudEventConstants.java b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersCloudEventConstants.java new file mode 100644 index 000000000..46f2a41d5 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersCloudEventConstants.java @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header; + +public class AsyncHeadersCloudEventConstants { + public static final String CONTENT_TYPE = "content-type"; + public static final String CONTENT_TYPE_DESC = "CloudEvent Content-Type Header"; + public static final String ID = "ce_id"; + public static final String ID_DESC = "CloudEvent Id Header"; + public static final String SPECVERSION = "ce_specversion"; + public static final String SPECVERSION_DESC = "CloudEvent Spec Version Header"; + public static final String SOURCE = "ce_source"; + public static final String SOURCE_DESC = "CloudEvent Source Header"; + public static final String SUBJECT = "ce_subject"; + public static final String SUBJECT_DESC = "CloudEvent Subject Header"; + public static final String TIME = "ce_time"; + public static final String TIME_DESC = "CloudEvent Time Header"; + public static final String TYPE = "ce_type"; + public static final String TYPE_DESC = "CloudEvent Payload Type Header"; +} diff --git a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersForCloudEventsBuilder.java b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersForCloudEventsBuilder.java index 1a22d86b1..2df864c47 100644 --- a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersForCloudEventsBuilder.java +++ b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/types/channel/operation/message/header/AsyncHeadersForCloudEventsBuilder.java @@ -6,6 +6,11 @@ import java.util.List; +/** + * Only used in combination with AsyncApiDocket bean + * If not, let us know by raising a GitHub issue + */ +@Deprecated public class AsyncHeadersForCloudEventsBuilder { private final AsyncHeaders headers; @@ -31,10 +36,10 @@ public AsyncHeadersForCloudEventsBuilder withContentTypeHeader( List contentTypeStringValues = contentTypeValues.stream().map(MimeType::toString).toList(); return withHeader( - "content-type", + AsyncHeadersCloudEventConstants.CONTENT_TYPE, contentTypeStringValues, exampleContentType.toString(), - "CloudEvent Content-Type Header"); + AsyncHeadersCloudEventConstants.CONTENT_TYPE_DESC); } public AsyncHeadersForCloudEventsBuilder withSpecVersionHeader(String specVersion) { @@ -42,7 +47,11 @@ public AsyncHeadersForCloudEventsBuilder withSpecVersionHeader(String specVersio } public AsyncHeadersForCloudEventsBuilder withSpecVersionHeader(String specVersion, List specValues) { - return withHeader("ce_specversion", specValues, specVersion, "CloudEvent Spec Version Header"); + return withHeader( + AsyncHeadersCloudEventConstants.SPECVERSION, + specValues, + specVersion, + AsyncHeadersCloudEventConstants.SPECVERSION_DESC); } public AsyncHeadersForCloudEventsBuilder withIdHeader(String idExample) { @@ -50,7 +59,8 @@ public AsyncHeadersForCloudEventsBuilder withIdHeader(String idExample) { } public AsyncHeadersForCloudEventsBuilder withIdHeader(String idExample, List idValues) { - return withHeader("ce_id", idValues, idExample, "CloudEvent Id Header"); + return withHeader( + AsyncHeadersCloudEventConstants.ID, idValues, idExample, AsyncHeadersCloudEventConstants.ID_DESC); } public AsyncHeadersForCloudEventsBuilder withTimeHeader(String timeExample) { @@ -58,7 +68,11 @@ public AsyncHeadersForCloudEventsBuilder withTimeHeader(String timeExample) { } public AsyncHeadersForCloudEventsBuilder withTimeHeader(String timeExample, List timeValues) { - return withHeader("ce_time", timeValues, timeExample, "CloudEvent Time Header"); + return withHeader( + AsyncHeadersCloudEventConstants.TIME, + timeValues, + timeExample, + AsyncHeadersCloudEventConstants.TIME_DESC); } public AsyncHeadersForCloudEventsBuilder withTypeHeader(String typeExample) { @@ -66,7 +80,11 @@ public AsyncHeadersForCloudEventsBuilder withTypeHeader(String typeExample) { } public AsyncHeadersForCloudEventsBuilder withTypeHeader(String typeExample, List typeValues) { - return withHeader("ce_type", typeValues, typeExample, "CloudEvent Payload Type Header"); + return withHeader( + AsyncHeadersCloudEventConstants.TYPE, + typeValues, + typeExample, + AsyncHeadersCloudEventConstants.TYPE_DESC); } public AsyncHeadersForCloudEventsBuilder withSourceHeader(String sourceExample) { @@ -74,7 +92,11 @@ public AsyncHeadersForCloudEventsBuilder withSourceHeader(String sourceExample) } public AsyncHeadersForCloudEventsBuilder withSourceHeader(String sourceExample, List sourceValues) { - return withHeader("ce_source", sourceValues, sourceExample, "CloudEvent Source Header"); + return withHeader( + AsyncHeadersCloudEventConstants.SOURCE, + sourceValues, + sourceExample, + AsyncHeadersCloudEventConstants.SOURCE_DESC); } public AsyncHeadersForCloudEventsBuilder withSubjectHeader(String subjectExample) { @@ -82,7 +104,11 @@ public AsyncHeadersForCloudEventsBuilder withSubjectHeader(String subjectExample } public AsyncHeadersForCloudEventsBuilder withSubjectHeader(String subjectExample, List subjectValues) { - return withHeader("ce_subject", subjectValues, subjectExample, "CloudEvent Subject Header"); + return withHeader( + AsyncHeadersCloudEventConstants.SUBJECT, + subjectValues, + subjectExample, + AsyncHeadersCloudEventConstants.SUBJECT_DESC); } public AsyncHeadersForCloudEventsBuilder withExtension( diff --git a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/producers/NestedProducer.java b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/producers/NestedProducer.java index 4900904ea..b4b45422b 100644 --- a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/producers/NestedProducer.java +++ b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/producers/NestedProducer.java @@ -6,9 +6,11 @@ import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.KafkaAsyncOperationBinding; import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.KafkaAsyncOperationBinding.KafkaAsyncKey; import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.KafkaAsyncOperationBinding.KafkaAsyncMessageBinding; +import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeadersCloudEventConstants; import io.github.stavshamir.springwolf.example.kafka.configuration.KafkaConfiguration; import io.github.stavshamir.springwolf.example.kafka.dtos.NestedPayloadDto; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; @@ -27,13 +29,41 @@ public class NestedProducer { description = "Custom, optional description defined in the AsyncPublisher annotation", headers = @AsyncOperation.Headers( - schemaName = "SpringKafkaDefaultHeaders", + schemaName = "SpringDefaultHeaderAndCloudEvent", values = { @AsyncOperation.Headers.Header( name = DEFAULT_CLASSID_FIELD_NAME, description = "Spring Type Id Header", value = "io.github.stavshamir.springwolf.example.kafka.dtos.NestedPayloadDto"), + @AsyncOperation.Headers.Header( + name = AsyncHeadersCloudEventConstants.CONTENT_TYPE, + description = AsyncHeadersCloudEventConstants.CONTENT_TYPE_DESC, + value = MediaType.APPLICATION_JSON_VALUE), + @AsyncOperation.Headers.Header( + name = AsyncHeadersCloudEventConstants.ID, + description = AsyncHeadersCloudEventConstants.ID_DESC, + value = "2c60089e-6f39-459d-8ced-2d6df7e4c03a"), + @AsyncOperation.Headers.Header( + name = AsyncHeadersCloudEventConstants.SPECVERSION, + description = AsyncHeadersCloudEventConstants.SPECVERSION_DESC, + value = "1.0"), + @AsyncOperation.Headers.Header( + name = AsyncHeadersCloudEventConstants.SOURCE, + description = AsyncHeadersCloudEventConstants.SOURCE_DESC, + value = "http://localhost"), + @AsyncOperation.Headers.Header( + name = AsyncHeadersCloudEventConstants.SUBJECT, + description = AsyncHeadersCloudEventConstants.SUBJECT_DESC, + value = "${spring.application.name}"), + @AsyncOperation.Headers.Header( + name = AsyncHeadersCloudEventConstants.TIME, + description = AsyncHeadersCloudEventConstants.TIME_DESC, + value = "2023-10-28 20:01:23+00:00"), + @AsyncOperation.Headers.Header( + name = AsyncHeadersCloudEventConstants.TYPE, + description = AsyncHeadersCloudEventConstants.TYPE_DESC, + value = "NestedPayloadDto.v1"), }))) @KafkaAsyncOperationBinding( clientId = "foo-clientId", diff --git a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json index cc59d8f3a..871168c0b 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json @@ -261,7 +261,7 @@ "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.kafka.dtos.NestedPayloadDto" }, "headers": { - "$ref": "#/components/schemas/SpringKafkaDefaultHeaders" + "$ref": "#/components/schemas/SpringDefaultHeaderAndCloudEvent" }, "bindings": { "kafka": { @@ -354,7 +354,7 @@ "properties": { }, "example": { } }, - "SpringKafkaDefaultHeaders": { + "SpringDefaultHeaderAndCloudEvent": { "type": "object", "properties": { "__TypeId__": { @@ -364,10 +364,73 @@ "enum": [ "io.github.stavshamir.springwolf.example.kafka.dtos.NestedPayloadDto" ] + }, + "ce_id": { + "type": "string", + "description": "CloudEvent Id Header", + "example": "2c60089e-6f39-459d-8ced-2d6df7e4c03a", + "enum": [ + "2c60089e-6f39-459d-8ced-2d6df7e4c03a" + ] + }, + "ce_source": { + "type": "string", + "description": "CloudEvent Source Header", + "example": "http://localhost", + "enum": [ + "http://localhost" + ] + }, + "ce_specversion": { + "type": "string", + "description": "CloudEvent Spec Version Header", + "example": "1.0", + "enum": [ + "1.0" + ] + }, + "ce_subject": { + "type": "string", + "description": "CloudEvent Subject Header", + "example": "Springwolf example project - Kafka", + "enum": [ + "Springwolf example project - Kafka" + ] + }, + "ce_time": { + "type": "string", + "description": "CloudEvent Time Header", + "example": "2023-10-28 20:01:23+00:00", + "enum": [ + "2023-10-28 20:01:23+00:00" + ] + }, + "ce_type": { + "type": "string", + "description": "CloudEvent Payload Type Header", + "example": "NestedPayloadDto.v1", + "enum": [ + "NestedPayloadDto.v1" + ] + }, + "content-type": { + "type": "string", + "description": "CloudEvent Content-Type Header", + "example": "application/json", + "enum": [ + "application/json" + ] } }, "example": { - "__TypeId__": "io.github.stavshamir.springwolf.example.kafka.dtos.NestedPayloadDto" + "__TypeId__": "io.github.stavshamir.springwolf.example.kafka.dtos.NestedPayloadDto", + "ce_id": "2c60089e-6f39-459d-8ced-2d6df7e4c03a", + "ce_source": "http://localhost", + "ce_specversion": "1.0", + "ce_subject": "Springwolf example project - Kafka", + "ce_time": "2023-10-28 20:01:23+00:00", + "ce_type": "NestedPayloadDto.v1", + "content-type": "application/json" } }, "SpringKafkaDefaultHeaders-AnotherPayloadDto": {