Skip to content

Commit

Permalink
Implement a builder for HttpClient, this will be useful for configuri…
Browse files Browse the repository at this point in the history
…ng the address resolver for service discovery.

The builder allows to retrofit the client redirect/connect handlers like done in SQL client.
  • Loading branch information
vietj committed Sep 24, 2023
1 parent 9bfa6d4 commit 97bdad5
Show file tree
Hide file tree
Showing 27 changed files with 630 additions and 367 deletions.
21 changes: 19 additions & 2 deletions src/main/asciidoc/http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ You can configure compressors according to your needs

=== Creating an HTTP client

You create an {@link io.vertx.core.http.HttpClientPool} instance with default options as follows:
You create an {@link io.vertx.core.http.HttpClient} instance with default options as follows:

[source,$lang]
----
Expand Down Expand Up @@ -881,6 +881,23 @@ For debugging purposes, network activity can be logged.

See the chapter on <<logging_network_activity, logging network activity>> for a detailed explanation.

=== Advanced HTTP client creation

You can pass options {@link io.vertx.core.Vertx#createHttpClient} methods to configure the HTTP client.

Alternatively you can build a client with the builder {@link io.vertx.core.http.HttpClientBuilder API} :

[source,$lang]
----
{@link examples.HTTPExamples#exampleClientBuilder01}
----

In addition to {@link io.vertx.core.http.HttpClientOptions} and {@link io.vertx.core.http.PoolOptions}, you
can set

- a connection event handler notified when the client <<_client_connections,connects>> to a server
- a redirection handler to implement an alternative HTTP <<_30x_redirection_handling,redirect>> behavior

=== Making requests

The http client is very flexible and there are various ways you can make requests with it.
Expand Down Expand Up @@ -1527,7 +1544,7 @@ The {@link io.vertx.core.http.HttpClientRequest#connection()} method returns the
{@link examples.HTTP2Examples#example18}
----

A connection handler can be set on the client to be notified when a connection has been established happens:
A connection handler can be set on a client builder to be notified when a connection has been established happens:

[source,$lang]
----
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/examples/HTTP2Examples.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,14 @@ public void example18(HttpClientRequest request) {
HttpConnection connection = request.connection();
}

public void example19(HttpClientPool client) {
client.connectionHandler(connection -> {
System.out.println("Connected to the server");
});
public void example19(Vertx vertx, HttpClientOptions options) {
vertx
.httpClientBuilder()
.with(options)
.withConnectHandler(connection -> {
System.out.println("Connected to the server");
})
.build();
}

public void example20(HttpConnection connection) {
Expand Down
35 changes: 22 additions & 13 deletions src/main/java/examples/HTTPExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,14 @@ public void exampleClientLogging(Vertx vertx) {
HttpClient client = vertx.createHttpClient(options);
}

public void exampleClientBuilder01(Vertx vertx, HttpClientOptions options) {
// Pretty much like vertx.createHttpClient(options)
HttpClient build = vertx
.httpClientBuilder()
.with(options)
.build();
}

public void example30(HttpClient client) {
client
.request(HttpMethod.GET, 8080, "myserver.mycompany.com", "/some-uri")
Expand Down Expand Up @@ -804,23 +812,24 @@ private String resolveURI(String base, String uriRef) {
throw new UnsupportedOperationException();
}

public void exampleFollowRedirect03(HttpClientPool client) {
public void exampleFollowRedirect03(Vertx vertx) {
HttpClient client = vertx.httpClientBuilder()
.withRedirectHandler(response -> {

client.redirectHandler(response -> {
// Only follow 301 code
if (response.statusCode() == 301 && response.getHeader("Location") != null) {

// Only follow 301 code
if (response.statusCode() == 301 && response.getHeader("Location") != null) {
// Compute the redirect URI
String absoluteURI = resolveURI(response.request().absoluteURI(), response.getHeader("Location"));

// Compute the redirect URI
String absoluteURI = resolveURI(response.request().absoluteURI(), response.getHeader("Location"));

// Create a new ready to use request that the client will use
return Future.succeededFuture(new RequestOptions().setAbsoluteURI(absoluteURI));
}
// Create a new ready to use request that the client will use
return Future.succeededFuture(new RequestOptions().setAbsoluteURI(absoluteURI));
}

// We don't redirect
return null;
});
// We don't redirect
return null;
})
.build();
}

public void example50(HttpClient client) {
Expand Down
19 changes: 14 additions & 5 deletions src/main/java/io/vertx/core/Vertx.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ default HttpServer createHttpServer() {
return createHttpServer(new HttpServerOptions());
}


/**
* Create a WebSocket client using default options
*
Expand All @@ -180,22 +179,32 @@ default WebSocketClient createWebSocketClient() {
*/
WebSocketClient createWebSocketClient(WebSocketClientOptions options);

/**
* Provide a builder for {@link HttpClient}, it can be used to configure advanced
* HTTP client settings like a redirect handler or a connection handler.
* <p>
* Example usage: {@code HttpClient client = vertx.httpClientBuilder().with(options).withConnectHandler(conn -> ...).build()}
*/
HttpClientBuilder httpClientBuilder();

/**
* Create a HTTP/HTTPS client using the specified client and pool options
*
* @param clientOptions the client options to use
* @param poolOptions the pool options to use
* @return the client
*/
HttpClientPool createHttpClient(HttpClientOptions clientOptions, PoolOptions poolOptions);
default HttpClient createHttpClient(HttpClientOptions clientOptions, PoolOptions poolOptions) {
return httpClientBuilder().with(clientOptions).with(poolOptions).build();
}

/**
* Create a HTTP/HTTPS client using the specified client options
*
* @param clientOptions the options to use
* @return the client
*/
default HttpClientPool createHttpClient(HttpClientOptions clientOptions) {
default HttpClient createHttpClient(HttpClientOptions clientOptions) {
return createHttpClient(clientOptions, new PoolOptions());
}

Expand All @@ -205,7 +214,7 @@ default HttpClientPool createHttpClient(HttpClientOptions clientOptions) {
* @param poolOptions the pool options to use
* @return the client
*/
default HttpClientPool createHttpClient(PoolOptions poolOptions) {
default HttpClient createHttpClient(PoolOptions poolOptions) {
return createHttpClient(new HttpClientOptions(), poolOptions);
}

Expand All @@ -214,7 +223,7 @@ default HttpClientPool createHttpClient(PoolOptions poolOptions) {
*
* @return the client
*/
default HttpClientPool createHttpClient() {
default HttpClient createHttpClient() {
return createHttpClient(new HttpClientOptions(), new PoolOptions());
}
/**
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/io/vertx/core/http/HttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.Future;
import io.vertx.core.net.ClientSSLOptions;

import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -45,7 +46,7 @@
* @author <a href="http://tfox.org">Tim Fox</a>
*/
@VertxGen
public interface HttpClient {
public interface HttpClient extends io.vertx.core.metrics.Measured {

/**
* Create an HTTP request to send to the server.
Expand Down Expand Up @@ -125,4 +126,13 @@ default Future<Void> shutdown() {
*/
Future<Void> shutdown(long timeout, TimeUnit timeUnit);

/**
* Update the client SSL options.
*
* Update only happens if the SSL options is valid.
*
* @param options the new SSL options
* @return a future signaling the update success
*/
Future<Void> updateSSLOptions(ClientSSLOptions options);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,43 @@
package io.vertx.core.http;

import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.net.ClientSSLOptions;
import io.vertx.core.net.SSLOptions;

import java.util.function.Function;

/**
* A builder for {@link HttpClient}.
*
* @author <a href="mailto:[email protected]">Julien Viet</a>
*/
@VertxGen
public interface HttpClientPool extends HttpClient, io.vertx.core.metrics.Measured {
public interface HttpClientBuilder {

/**
* Update the client SSL options.
*
* Update only happens if the SSL options is valid.
*
* @param options the new SSL options
* @return a future signaling the update success
* Configure the client options.
* @param options the client options
* @return a reference to this, so the API can be used fluently
*/
Future<Void> updateSSLOptions(ClientSSLOptions options);
@Fluent
HttpClientBuilder with(HttpClientOptions options);

/**
* Configure the client with the given pool {@code options}.
* @param options the pool options
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpClientBuilder with(PoolOptions options);

/**
* Set a connection handler for the client. This handler is called when a new connection is established.
*
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpClientPool connectionHandler(Handler<HttpConnection> handler);
HttpClientBuilder withConnectHandler(Handler<HttpConnection> handler);

/**
* Set a redirect handler for the http client.
Expand All @@ -61,12 +69,12 @@ public interface HttpClientPool extends HttpClient, io.vertx.core.metrics.Measur
* @return a reference to this, so the API can be used fluently
*/
@Fluent
HttpClientPool redirectHandler(Function<HttpClientResponse, Future<RequestOptions>> handler);
HttpClientBuilder withRedirectHandler(Function<HttpClientResponse, Future<RequestOptions>> handler);

/**
* @return the current redirect handler.
* Build and return the client.
* @return the client as configured by this builder
*/
@GenIgnore
Function<HttpClientResponse, Future<RequestOptions>> redirectHandler();
HttpClient build();

}
22 changes: 0 additions & 22 deletions src/main/java/io/vertx/core/http/impl/CleanableHttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
*/
package io.vertx.core.http.impl;

import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.http.*;
import io.vertx.core.impl.VertxInternal;
Expand All @@ -26,7 +23,6 @@
import java.lang.ref.Cleaner;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
* A lightweight proxy of Vert.x {@link HttpClient} that can be collected by the garbage collector and release
Expand Down Expand Up @@ -70,24 +66,6 @@ public Future<Void> updateSSLOptions(ClientSSLOptions options) {
return delegate.updateSSLOptions(options);
}

@Override
@Fluent
public HttpClientPool connectionHandler(Handler<HttpConnection> handler) {
return delegate.connectionHandler(handler);
}

@Override
@Fluent
public HttpClientPool redirectHandler(Function<HttpClientResponse, Future<RequestOptions>> handler) {
return delegate.redirectHandler(handler);
}

@Override
@GenIgnore
public Function<HttpClientResponse, Future<RequestOptions>> redirectHandler() {
return delegate.redirectHandler();
}

@Override
public Future<Void> shutdown(long timeout, TimeUnit timeUnit) {
if (timeout < 0L) {
Expand Down
Loading

0 comments on commit 97bdad5

Please sign in to comment.