cloudevents/sdk-java

Extension of Quarkus example with structured content mode

sjaakd opened this issue · 17 comments

I like the Quarkus example.

However, it seems to use the Binary Content Mode. I however require the Structured Content Mode. Initially I did not even notice that the binary mode left out the metadata from the body. I did not even notice initially there were 2 modes.

It took me quite some time that all that's required is adding the annotation @Consumes( JsonFormat.CONTENT_TYPE ) to the client:

@Path( "/notify" )
@RegisterRestClient
public interface BrokerClient {

    @POST
    @Consumes( JsonFormat.CONTENT_TYPE )
    void emit( CloudEvent event);
}

Will trigger sending the request in the Structured Content Mode.

Likewise adding a @Consumes( JsonFormat.CONTENT_TYPE ) to the server:

    @POST
    @Path( "notify" )
    @Consumes( JsonFormat.CONTENT_TYPE )
    public Response create( CloudEvent event ) {
         // logic
    }

Fixes the server part. All the more confusing is that this reference mentions the Quarkus example (while discussing the structured content mode).

Suggestion: update the README.md or extend the example.

Hi @sjaakd, thanks for reporting!

I like the idea of extending the example on the client side to show how to produce both content modes, on the server side perhaps having an example server that can transparently consume both content modes would be the best option.

@matejvasek is there any way we can make a generic example for a quarkus server endpoint that works transparently for both binary and structured content modes?

@sjaakd would you be willing to contribute this documentation?

Hi @sjaakd, thanks for reporting!

I like the idea of extending the example on the client side to show how to produce both content modes, on the server side perhaps having an example server that can transparently consume both content modes would be the best option.

@matejvasek is there any way we can make a generic example for a quarkus server endpoint that works transparently for both binary and structured content modes?

@sjaakd would you be willing to contribute this documentation?

just add:

diff --git a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java
index 788e223..4af33d0 100644
--- a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java
+++ b/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/resources/UserResource.java
@@ -3,6 +3,7 @@ package io.cloudevents.examples.quarkus.resources;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.cloudevents.CloudEvent;
 import io.cloudevents.examples.quarkus.model.User;
+import io.cloudevents.jackson.JsonFormat;
 import io.cloudevents.jackson.PojoCloudEventDataMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -17,8 +18,8 @@ import java.util.HashMap;
 import java.util.Map;
 
 @Path("/users")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
+@Consumes({MediaType.APPLICATION_JSON, JsonFormat.CONTENT_TYPE})
+@Produces({MediaType.APPLICATION_JSON})
 public class UserResource {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class);

I'd like to re-open this issue since we are unable to produces CloudEvents in a structured fashion.

To repro we simply change src/main/java/io/cloudevents/examples/quarkus/client/UserClient.java to @Produces(JsonFormat.CONTENT_TYPE).

We expect the full content of the cloudevent to be in the payload, but instead we deliver in binary mode, with special headers added to the http (for example ce-type or ce-contenttype).

Is there something I'm missing?

@nitroin does this comment help?

// This will emit binary encoded events.
// To use structured JSON encoding use @Produces(JsonFormat.CONTENT_TYPE).
@POST
@Produces(MediaType.APPLICATION_JSON)
void emit(CloudEvent event);

That comment was exactly the one that suggests changing to @Produces(JsonFormat.CONTENT_TYPE) to have structured mode.

That's apparently the only change that's needed (afaik) - but I failed: to verify I simply setup a beeceptor.com endpoint to inspect the final/effective result.

Dropping in @Consume(JsonFormat.CONTENT_TYPE) seems to work ok? But I'm struggling to understand if this is the expected behavior (and thus better documented).

I also had the same issues with @Produces(JsonFormat.CONTENT_TYPE), to fix it I had to wrap the CloudEvent object in an Entity object as described by the documentation:

Entity<CloudEvent> entity = Entity.entity(cloudEvent, JsonFormat.CONTENT_TYPE)

I'm not sure if this is the behaviour that most people would expect though

I've also created this repro project to reproduce the issue mentioned above.

Hey, I have created a PR to generate both event modes and I have also documented it in the README.
I hope you find the PR useful.

Thanks @nitroin for your reproducer and @ruromero for the PR

@pierDipi sorry to be pedantic but the suggested and documented way to emit structured events does not work as expected.

Or maybe I'am missing something: https://github.com/nitroin/cloudevents-quarkus-structured-repro/blob/main/src/main/java/org/repro/ReproRestClient.java#L19-L21

@pierDipi sorry to be pedantic but the suggested and documented way to emit structured events does not work as expected.

Or maybe I'am missing something: https://github.com/nitroin/cloudevents-quarkus-structured-repro/blob/main/src/main/java/org/repro/ReproRestClient.java#L19-L21

Have you tried defining the event as a CloudEvent type instead of Object?

Have you tried defining the event as a CloudEvent type instead of Object?

Yep. Sadly with the same outcome.

The curious thinghy to note here is that when I first checkout this very repo I fixed the behavior only by adding @Consume(JsonFormat.CONTENT_TYPE) (as for this comment).

Starting from a scratch quarkus create app instead resulted in the binary always been dispatched.

Today I've played a little bit with the repro repo and I found that using the "deprecated" non-reactive rest-client fixed the issue. (from quarkus-rest-client-reactive-jackson to quarkus-rest-client-jackson).

Maybe I should open a related issue on the quarkus repo?

After further investigation removing:

    <dependency>
      <groupId>io.cloudevents</groupId>
      <artifactId>cloudevents-http-restful-ws</artifactId>
      <version>${cloudevents.version}</version>
    </dependency>

Results in a working example with the reactive rest client.

@nitroin do you think we can improve the documentation?

A sample project correctly setup'd with quarkus-reactive would help for sure. I can open a PR if this sound cool for you.

Sounds good to me @nitroin