Skip to content

Commit

Permalink
Merge pull request #32881 from Sgitario/httpoptions_api
Browse files Browse the repository at this point in the history
Support registering a HttpClientOptions in REST Client Reactive API
  • Loading branch information
Sgitario authored Apr 25, 2023
2 parents 725bdab + 1ff505a commit aee982d
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 12 deletions.
15 changes: 4 additions & 11 deletions docs/src/main/asciidoc/rest-client-reactive.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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<HttpClientOptions> {
@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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<? extends HttpClientOptions> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -198,6 +200,23 @@ public QuarkusRestClientBuilder clientHeadersFactory(ClientHeadersFactory client
return this;
}

@Override
public QuarkusRestClientBuilder httpClientOptions(Class<? extends HttpClientOptions> 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> T build(Class<T> clazz) throws IllegalStateException, RestClientDefinitionException {
return proxy.build(clazz);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<HttpClientOptions> {

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

0 comments on commit aee982d

Please sign in to comment.