-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rest Client Reactive: Add reactive flavor for ClientHeadersFactory #21807
Conversation
@michalszynkiewicz this PR proposes to create a version of ClientHeadersFactory for reactive by implementing the The benefit is that we can reuse the same annotation ( In summary, by extending If you're not happy with, the alternative is to:
Let me know your thoughts about it. |
This workflow status is outdated as a new workflow run has been triggered. Failing Jobs - Building 6d054a9
Failures⚙️ Initial JDK 11 Build #- Failing: extensions/resteasy-reactive/rest-client-reactive/runtime
! Skipped: devtools/bom-descriptor-json docs extensions/oidc-client-reactive-filter/deployment and 12 more 📦 extensions/resteasy-reactive/rest-client-reactive/runtime✖ |
6d054a9
to
fffde59
Compare
This workflow status is outdated as a new workflow run has been triggered. Failing Jobs - Building fffde59
Full information is available in the Build summary check run. Failures⚙️ JVM Tests - JDK 11 #- Failing: extensions/resteasy-reactive/rest-client-reactive/deployment
! Skipped: extensions/oidc-client-reactive-filter/deployment extensions/resteasy-reactive/rest-client-reactive-jackson/deployment integration-tests/micrometer-prometheus and 5 more 📦 extensions/resteasy-reactive/rest-client-reactive/deployment✖
✖
⚙️ JVM Tests - JDK 11 Windows #- Failing: extensions/resteasy-reactive/rest-client-reactive/deployment
! Skipped: extensions/oidc-client-reactive-filter/deployment extensions/resteasy-reactive/rest-client-reactive-jackson/deployment integration-tests/micrometer-prometheus and 5 more 📦 extensions/resteasy-reactive/rest-client-reactive/deployment✖
✖
⚙️ JVM Tests - JDK 17 #- Failing: extensions/resteasy-reactive/rest-client-reactive/deployment
! Skipped: extensions/oidc-client-reactive-filter/deployment extensions/resteasy-reactive/rest-client-reactive-jackson/deployment integration-tests/micrometer-prometheus and 5 more 📦 extensions/resteasy-reactive/rest-client-reactive/deployment✖
✖
|
fffde59
to
9ebba56
Compare
...tive/runtime/src/main/java/io/quarkus/rest/client/reactive/ReactiveClientHeadersFactory.java
Outdated
Show resolved
Hide resolved
...tive/runtime/src/main/java/io/quarkus/rest/client/reactive/ReactiveClientHeadersFactory.java
Show resolved
Hide resolved
@@ -63,7 +65,21 @@ public void filter(ClientRequestContext requestContext) { | |||
} | |||
|
|||
if (clientHeadersFactory != null) { | |||
incomingHeaders = clientHeadersFactory.update(incomingHeaders, headers); | |||
if (clientHeadersFactory instanceof ReactiveClientHeadersFactory | |||
&& requestContext instanceof ResteasyReactiveClientRequestContext) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this filter should always work with RestEasyReactiveClientRequestContext
, no? I don't think we need to check it with instanceof
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so... but I thought we could be extra safe here. However, will remove the instanceof.
Added reactive flavor of `ClientHeadersFactory` that allows doing blocking operations. For example: [source, java] ---- package org.acme.rest.client; import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory; import javax.enterprise.context.ApplicationScoped; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import java.util.UUID; @ApplicationScoped public class GetTokenReactiveClientHeadersFactory extends ReactiveClientHeadersFactory { @Inject Service service; @OverRide public Uni<MultivaluedMap<String, String>> getHeaders(MultivaluedMap<String, String> incomingHeaders) { return Uni.createFrom().item(() -> { MultivaluedHashMap<String, String> newHeaders = new MultivaluedHashMap<>(); // perform blocking call newHeaders.add(HEADER_NAME, service.getToken()); return newHeaders; }); } } ---- Fixes quarkusio#20001
9ebba56
to
87be3ed
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @Sgitario !
return Uni.createFrom().item(() -> { | ||
MultivaluedHashMap<String, String> newHeaders = new MultivaluedHashMap<>(); | ||
// perform blocking call | ||
newHeaders.add(HEADER_NAME, service.getToken()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi,
I am sorry that I kind of hijack this already merged PR, but IMHO the ReactiveClientHeadersFactory
does not work as expected.
Why has the service.getToken()
to be a blocking call?
In my case I wanted to call the auth server where I obtain a token also in a reactive manner by using an reactive rest client.
Therefore my code would look like this:
override fun getHeaders(incomingHeaders: MultivaluedMap<String, String>?): Uni<MultivaluedMap<String, String>> {
// Utilizing the reactive mutiny api :-), which unfortunately does not work....
return clientTokenFetcher.getClientToken().onItem().transform {
MultivaluedHashMap<String, String>().apply {
add(HttpHeaders.CACHE_CONTROL, "no-cache")
add(HttpHeaders.CONTENT_TYPE, "text/plain")
add(HttpHeaders.AUTHORIZATION, it.authHeader)
}
}
}
Unfortunately this does not work, while this is working:
override fun getHeaders(incomingHeaders: MultivaluedMap<String, String>?): Uni<MultivaluedMap<String, String>> {
return Uni.createFrom().item(
MultivaluedHashMap<String, String>().apply {
add(HttpHeaders.CACHE_CONTROL, "no-cache")
add(HttpHeaders.CONTENT_TYPE, "text/plain")
// Make this a blocking call ;-(
add(HttpHeaders.AUTHORIZATION, clientTokenFetcher.getClientToken().await().atMost(Duration.ofMillis(500)).authHeader)
}
)
}
Can someone please tell me how to stay fully reactive and make it work without the blocking within the Uni?
The code above is written in kotlin, but I could also convert it into Java if that helps you...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The service.getToken()
does not have to be a blocking call. This example was only intended to explain how to inject headers from a blocking service to Resteasy Rest Client.
Also, I tried to reproduce your scenario and it worked for me:
@ApplicationScoped
public static class Service {
public Uni<String> getValue() {
return Uni.createFrom().item(HEADER_VALUE);
}
}
@RegisterClientHeaders(CustomReactiveClientHeadersFactory.class)
public interface Client {
@GET
String getWithHeader();
}
public static class CustomReactiveClientHeadersFactory extends ReactiveClientHeadersFactory {
@Inject
Service service;
@Override
public Uni<MultivaluedMap<String, String>> getHeaders(MultivaluedMap<String, String> incomingHeaders) {
return service.getValue().onItem().transform(value -> {
MultivaluedHashMap<String, String> newHeaders = new MultivaluedHashMap<>();
newHeaders.add(HEADER_NAME, value);
return newHeaders;
});
}
}
This is verified using this test https://github.com/quarkusio/quarkus/blob/main/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/ReactiveClientHeadersFromProviderTest.java
Therefore, it would be good to open an issue with a reproducer, so we can exactly see what is going on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Sgitario ,
thanks for your quick response:
Here you can find an example which reproduces my issue:
https://github.com/SimonScholz/ReactiveClientHeadersFactory/blob/b1a7a07c13afa9168b8897653fa27ce0f4cf3be3/src/test/kotlin/io/github/simonscholz/ReactiveResourceTest.kt#L82
In this example I'd use a reactive rest client in order to obtain a token, which is then used by the BeverageRequestHeaderFactory
to generate a proper Authorization header.
The ReactiveResourceTest
shows that this does not work.
I'll also create an issue later on, but wanted to inform you about my example in advance.
Thanks and regards,
Simon
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added reactive flavor of
ClientHeadersFactory
that allows doing blocking operations. For example:Resolves #20001