From 1ff505aea37deef3bfd22183eca68598729efda0 Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 25 Apr 2023 14:30:37 +0200 Subject: [PATCH] Support registering a HttpClientOptions in REST Client Reactive API Similar to https://github.com/quarkusio/quarkus/pull/32880, we can extend the new REST Client Reactive API to provide a custom HttpClientOptions. --- .../main/asciidoc/rest-client-reactive.adoc | 15 ++++-------- ...sViaProgrammaticallyClientCreatedTest.java | 17 +++++++++++++- .../reactive/QuarkusRestClientBuilder.java | 17 ++++++++++++++ .../runtime/QuarkusRestClientBuilderImpl.java | 19 +++++++++++++++ .../HttpClientOptionsContextResolver.java | 23 +++++++++++++++++++ 5 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/context/HttpClientOptionsContextResolver.java diff --git a/docs/src/main/asciidoc/rest-client-reactive.adoc b/docs/src/main/asciidoc/rest-client-reactive.adoc index d2f0f4d0c5705..83a97652fc686 100644 --- a/docs/src/main/asciidoc/rest-client-reactive.adoc +++ b/docs/src/main/asciidoc/rest-client-reactive.adoc @@ -497,24 +497,17 @@ public class ExtensionsResource { private final ExtensionsService extensionsService; public ExtensionsResource() { + HttpClientOptions options = new HttpClientOptions(); + // ... + extensionsService = QuarkusRestClientBuilder.newBuilder() .baseUri(URI.create("https://stage.code.quarkus.io/api")) - .register(CustomHttpClientOptions.class) <1> + .httpClientOptions(options) <1> .build(ExtensionsService.class); } // ... } - -public class CustomHttpClientOptions implements ContextResolver { - - @Override - public HttpClientOptions getContext(Class aClass) { - HttpClientOptions options = new HttpClientOptions(); - // ... - return options; - } -} ---- <1> the client will use the registered HTTP Client options over the HTTP Client options provided via CDI if any. diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomHttpOptionsViaProgrammaticallyClientCreatedTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomHttpOptionsViaProgrammaticallyClientCreatedTest.java index f5d36c89e09fa..6c742f2405913 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomHttpOptionsViaProgrammaticallyClientCreatedTest.java +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/CustomHttpOptionsViaProgrammaticallyClientCreatedTest.java @@ -30,7 +30,7 @@ public class CustomHttpOptionsViaProgrammaticallyClientCreatedTest { .withApplicationRoot((jar) -> jar.addClasses(Client.class)); @Test - void shouldUseCustomHttpOptions() { + void shouldUseCustomHttpOptionsUsingProvider() { // First verify the standard configuration assertThat(QuarkusRestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class).get()) .isEqualTo(EXPECTED_VALUE); @@ -43,6 +43,21 @@ void shouldUseCustomHttpOptions() { assertThatThrownBy(() -> client.get()).hasMessageContaining("HTTP header is larger than 1 bytes."); } + @Test + void shouldUseCustomHttpOptionsUsingAPI() { + // First verify the standard configuration + assertThat(QuarkusRestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class).get()) + .isEqualTo(EXPECTED_VALUE); + + // Now, it should fail if we use a custom http client options with a very limited max header size: + HttpClientOptions options = new HttpClientOptions(); + options.setMaxHeaderSize(1); // this is just to verify that this HttpClientOptions is indeed used. + Client client = QuarkusRestClientBuilder.newBuilder().baseUri(baseUri) + .httpClientOptions(options) + .build(Client.class); + assertThatThrownBy(() -> client.get()).hasMessageContaining("HTTP header is larger than 1 bytes."); + } + @Path("/") @ApplicationScoped public static class Resource { diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java index d06170a928b3f..e562dd9a1ccbd 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java @@ -19,6 +19,7 @@ import io.quarkus.rest.client.reactive.runtime.QuarkusRestClientBuilderImpl; import io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl; +import io.vertx.core.http.HttpClientOptions; /** * This is the main entry point for creating a Type Safe Quarkus Rest Client. @@ -233,6 +234,22 @@ static QuarkusRestClientBuilder newBuilder() { */ QuarkusRestClientBuilder clientHeadersFactory(ClientHeadersFactory clientHeadersFactory); + /** + * Specifies the HTTP client options to use. + * + * @param httpClientOptionsClass the HTTP client options to use. + * @return the current builder + */ + QuarkusRestClientBuilder httpClientOptions(Class httpClientOptionsClass); + + /** + * Specifies the HTTP client options to use. + * + * @param httpClientOptions the HTTP client options to use. + * @return the current builder + */ + QuarkusRestClientBuilder httpClientOptions(HttpClientOptions httpClientOptions); + /** * Based on the configured QuarkusRestClientBuilder, creates a new instance of the given REST interface to invoke API calls * against. diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java index f901090f2f652..81062447ce18a 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java @@ -17,6 +17,8 @@ import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; import io.quarkus.rest.client.reactive.runtime.context.ClientHeadersFactoryContextResolver; +import io.quarkus.rest.client.reactive.runtime.context.HttpClientOptionsContextResolver; +import io.vertx.core.http.HttpClientOptions; public class QuarkusRestClientBuilderImpl implements QuarkusRestClientBuilder { @@ -198,6 +200,23 @@ public QuarkusRestClientBuilder clientHeadersFactory(ClientHeadersFactory client return this; } + @Override + public QuarkusRestClientBuilder httpClientOptions(Class httpClientOptionsClass) { + HttpClientOptions bean = BeanGrabber.getBeanIfDefined(httpClientOptionsClass); + if (bean == null) { + throw new IllegalArgumentException("Failed to instantiate the HTTP client options " + httpClientOptionsClass + + ". Make sure the bean is properly configured for CDI injection."); + } + + return httpClientOptions(bean); + } + + @Override + public QuarkusRestClientBuilder httpClientOptions(HttpClientOptions httpClientOptions) { + proxy.register(new HttpClientOptionsContextResolver(httpClientOptions)); + return this; + } + @Override public T build(Class clazz) throws IllegalStateException, RestClientDefinitionException { return proxy.build(clazz); diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/context/HttpClientOptionsContextResolver.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/context/HttpClientOptionsContextResolver.java new file mode 100644 index 0000000000000..c3765ce1a7182 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/context/HttpClientOptionsContextResolver.java @@ -0,0 +1,23 @@ +package io.quarkus.rest.client.reactive.runtime.context; + +import jakarta.ws.rs.ext.ContextResolver; + +import io.vertx.core.http.HttpClientOptions; + +public class HttpClientOptionsContextResolver implements ContextResolver { + + private final HttpClientOptions component; + + public HttpClientOptionsContextResolver(HttpClientOptions component) { + this.component = component; + } + + @Override + public HttpClientOptions getContext(Class wantedClass) { + if (wantedClass.equals(HttpClientOptions.class)) { + return component; + } + + return null; + } +}