sdk-java icon indicating copy to clipboard operation
sdk-java copied to clipboard

Extension of Quarkus example with structured content mode

Open sjaakd opened this issue 2 years ago • 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.

sjaakd avatar Jul 14 '22 16:07 sjaakd

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?

pierDipi avatar Jul 18 '22 07:07 pierDipi

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

matejvasek avatar Jul 18 '22 18:07 matejvasek

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?

manuelserradev avatar Dec 12 '22 15:12 manuelserradev

@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

pierDipi avatar Dec 16 '22 08:12 pierDipi

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

manuelserradev avatar Dec 19 '22 13:12 manuelserradev

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

fnurglewitz avatar Jan 19 '23 13:01 fnurglewitz

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

manuelserradev avatar Jan 19 '23 14:01 manuelserradev

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.

ruromero avatar Jan 24 '23 15:01 ruromero

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

pierDipi avatar Jan 24 '23 15:01 pierDipi

@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

manuelserradev avatar Jan 24 '23 16:01 manuelserradev

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

ruromero avatar Jan 24 '23 16:01 ruromero

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 avatar Jan 24 '23 16:01 manuelserradev

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 avatar Jan 25 '23 09:01 manuelserradev

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.

manuelserradev avatar Jan 25 '23 10:01 manuelserradev

@nitroin do you think we can improve the documentation?

pierDipi avatar Feb 07 '23 11:02 pierDipi

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

manuelserradev avatar Feb 09 '23 09:02 manuelserradev

Sounds good to me @nitroin

pierDipi avatar Mar 03 '23 11:03 pierDipi