cloudevents / sdk-java

Java SDK for CloudEvents
https://cloudevents.github.io/sdk-java/
Apache License 2.0
390 stars 159 forks source link

Extension of Quarkus example with structured content mode #465

Open sjaakd opened 2 years ago

sjaakd commented 2 years ago

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.

pierDipi commented 2 years ago

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?

matejvasek commented 2 years ago

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);
manuelserradev commented 1 year ago

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?

pierDipi commented 1 year ago

@nitroin does this comment help?

https://github.com/cloudevents/sdk-java/blob/354f7a16ef411940a390a0ac935e431cdc938e1a/examples/restful-ws-quarkus/src/main/java/io/cloudevents/examples/quarkus/client/UserClient.java#L15-L19

manuelserradev commented 1 year ago

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).

fnurglewitz commented 1 year ago

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

manuelserradev commented 1 year ago

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

ruromero commented 1 year ago

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.

pierDipi commented 1 year ago

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

manuelserradev commented 1 year ago

@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

ruromero commented 1 year ago

@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?

manuelserradev commented 1 year ago

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.

manuelserradev commented 1 year ago

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?

manuelserradev commented 1 year ago

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.

pierDipi commented 1 year ago

@nitroin do you think we can improve the documentation?

manuelserradev commented 1 year ago

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

pierDipi commented 1 year ago

Sounds good to me @nitroin