Update WebClient builder
Leave only one static, no-arg build() method for access to a Builder. URI-related preferences are now exposed on the builder itself. Improve Javadoc with base URI examples.
This commit is contained in:
parent
acf511ac0e
commit
82a34f4b24
|
|
@ -22,6 +22,7 @@ import java.time.ZoneId;
|
|||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -143,6 +144,11 @@ class DefaultWebClient implements WebClient {
|
|||
return uri(getUriBuilderFactory().expand(uriTemplate, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HeaderSpec uri(String uriTemplate, Map<String, ?> uriVariables) {
|
||||
return uri(getUriBuilderFactory().expand(uriTemplate, uriVariables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HeaderSpec uri(Function<UriBuilderFactory, URI> uriFunction) {
|
||||
return uri(uriFunction.apply(getUriBuilderFactory()));
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.web.reactive.function.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
|
|
@ -35,49 +36,38 @@ import org.springframework.web.util.UriBuilderFactory;
|
|||
*/
|
||||
class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private Map<String, ?> defaultUriVariables;
|
||||
|
||||
private UriBuilderFactory uriBuilderFactory;
|
||||
|
||||
private HttpHeaders defaultHeaders;
|
||||
|
||||
private MultiValueMap<String, String> defaultCookies;
|
||||
|
||||
private ClientHttpConnector connector;
|
||||
|
||||
private ExchangeStrategies exchangeStrategies = ExchangeStrategies.withDefaults();
|
||||
|
||||
private ExchangeFunction exchangeFunction;
|
||||
|
||||
private HttpHeaders defaultHeaders;
|
||||
|
||||
private MultiValueMap<String, String> defaultCookies;
|
||||
|
||||
|
||||
public DefaultWebClientBuilder() {
|
||||
this(new DefaultUriBuilderFactory());
|
||||
@Override
|
||||
public WebClient.Builder baseUrl(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultWebClientBuilder(String baseUrl) {
|
||||
this(new DefaultUriBuilderFactory(baseUrl));
|
||||
@Override
|
||||
public WebClient.Builder defaultUriVariables(Map<String, ?> defaultUriVariables) {
|
||||
this.defaultUriVariables = defaultUriVariables;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultWebClientBuilder(UriBuilderFactory uriBuilderFactory) {
|
||||
Assert.notNull(uriBuilderFactory, "UriBuilderFactory is required.");
|
||||
@Override
|
||||
public WebClient.Builder uriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
|
||||
this.uriBuilderFactory = uriBuilderFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WebClient.Builder clientConnector(ClientHttpConnector connector) {
|
||||
this.connector = connector;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient.Builder exchangeStrategies(ExchangeStrategies strategies) {
|
||||
Assert.notNull(strategies, "ExchangeStrategies is required.");
|
||||
this.exchangeStrategies = strategies;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient.Builder exchangeFunction(ExchangeFunction exchangeFunction) {
|
||||
this.exchangeFunction = exchangeFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -101,10 +91,40 @@ class DefaultWebClientBuilder implements WebClient.Builder {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient.Builder clientConnector(ClientHttpConnector connector) {
|
||||
this.connector = connector;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient.Builder exchangeStrategies(ExchangeStrategies strategies) {
|
||||
Assert.notNull(strategies, "ExchangeStrategies is required.");
|
||||
this.exchangeStrategies = strategies;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient.Builder exchangeFunction(ExchangeFunction exchangeFunction) {
|
||||
this.exchangeFunction = exchangeFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient build() {
|
||||
return new DefaultWebClient(initExchangeFunction(),
|
||||
this.uriBuilderFactory, this.defaultHeaders, this.defaultCookies);
|
||||
return new DefaultWebClient(initExchangeFunction(), initUriBuilderFactory(),
|
||||
this.defaultHeaders, this.defaultCookies);
|
||||
}
|
||||
|
||||
private UriBuilderFactory initUriBuilderFactory() {
|
||||
if (this.uriBuilderFactory != null) {
|
||||
return this.uriBuilderFactory;
|
||||
}
|
||||
DefaultUriBuilderFactory factory = this.baseUrl != null ?
|
||||
new DefaultUriBuilderFactory(this.baseUrl) : new DefaultUriBuilderFactory();
|
||||
|
||||
factory.setDefaultUriVariables(this.defaultUriVariables);
|
||||
return factory;
|
||||
}
|
||||
|
||||
private ExchangeFunction initExchangeFunction() {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.springframework.web.reactive.function.client;
|
|||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
|
@ -30,7 +31,6 @@ import org.springframework.http.client.reactive.ClientHttpConnector;
|
|||
import org.springframework.http.client.reactive.ClientHttpRequest;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.BodyInserter;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
import org.springframework.web.util.UriBuilderFactory;
|
||||
|
||||
/**
|
||||
|
|
@ -38,20 +38,13 @@ import org.springframework.web.util.UriBuilderFactory;
|
|||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* // Create ExchangeFunction (application-wide)
|
||||
* // Initialize the client
|
||||
*
|
||||
* ClientHttpConnector connector = new ReactorClientHttpConnector();
|
||||
* ExchangeFunction exchangeFunction = ExchangeFunctions.create(connector);
|
||||
*
|
||||
* // Create WebClient (per base URI)
|
||||
*
|
||||
* String baseUri = "http://abc.com";
|
||||
* UriBuilderFactory factory = new DefaultUriBuilderFactory(baseUri);
|
||||
* WebClient operations = WebClient.create(exchangeFunction, factory);
|
||||
* WebClient client = WebClient.create("http://abc.com");
|
||||
*
|
||||
* // Perform requests...
|
||||
*
|
||||
* Mono<String> result = operations.get()
|
||||
* Mono<String> result = client.get()
|
||||
* .uri("/foo")
|
||||
* .exchange()
|
||||
* .then(response -> response.bodyToMono(String.class));
|
||||
|
|
@ -118,24 +111,49 @@ public interface WebClient {
|
|||
// Static, factory methods
|
||||
|
||||
/**
|
||||
* Shortcut for:
|
||||
* <pre class="code">
|
||||
* WebClient client = builder().build();
|
||||
* </pre>
|
||||
* Create a new {@code WebClient} with no default, shared preferences across
|
||||
* requests such as base URI, default headers, and others.
|
||||
*/
|
||||
static WebClient create() {
|
||||
return new DefaultWebClientBuilder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for:
|
||||
* Configure a base URI for requests performed through the client for
|
||||
* example to avoid repeating the same host, port, base path, or even
|
||||
* query parameters with every request.
|
||||
*
|
||||
* <p>Given the following initialization:
|
||||
* <pre class="code">
|
||||
* WebClient client = builder(baseUrl).build();
|
||||
* WebClient client = WebClient.create("http://abc.com/v1");
|
||||
* </pre>
|
||||
*
|
||||
* <p>A base URI is applied when using a URI template:
|
||||
* <pre class="code">
|
||||
*
|
||||
* // GET http://abc.com/v1/accounts/43
|
||||
*
|
||||
* Mono<Account> result = client.get()
|
||||
* .uri("/accounts/{id}", 43)
|
||||
* .exchange()
|
||||
* .then(response -> response.bodyToMono(String.class));
|
||||
* </pre>
|
||||
*
|
||||
* <p>It is also applied when using a {@link UriBuilderFactory}:
|
||||
* <pre class="code">
|
||||
|
||||
* // GET http://abc.com/v1/accounts?q=12
|
||||
*
|
||||
* Mono<Account> result = client.get()
|
||||
* .uri(factory -> factory.uriString("/accounts").queryParam("q", "12").build())
|
||||
* .exchange()
|
||||
* .then(response -> response.bodyToMono(String.class));
|
||||
* </pre>
|
||||
*
|
||||
* @param baseUrl the base URI for all requests
|
||||
*/
|
||||
static WebClient create(String baseUrl) {
|
||||
return new DefaultWebClientBuilder(baseUrl).build();
|
||||
return new DefaultWebClientBuilder().baseUrl(baseUrl).build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -145,27 +163,6 @@ public interface WebClient {
|
|||
return new DefaultWebClientBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a {@code WebClient} builder with a base URI to be used as the
|
||||
* base for expanding URI templates during exchanges. The given String
|
||||
* is used to create an instance of {@link DefaultUriBuilderFactory} whose
|
||||
* {@link DefaultUriBuilderFactory#DefaultUriBuilderFactory(String)
|
||||
* constructor} provides more details on how the base URI is applied.
|
||||
* @param baseUrl the base URI for all requests
|
||||
*/
|
||||
static WebClient.Builder builder(String baseUrl) {
|
||||
return new DefaultWebClientBuilder(baseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a {@code WebClient} builder with the {@link UriBuilderFactory}
|
||||
* to use for expanding URI templates during exchanges.
|
||||
* @param uriBuilderFactory the factory to use
|
||||
*/
|
||||
static WebClient.Builder builder(UriBuilderFactory uriBuilderFactory) {
|
||||
return new DefaultWebClientBuilder(uriBuilderFactory);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A mutable builder for a {@link WebClient}.
|
||||
|
|
@ -173,30 +170,34 @@ public interface WebClient {
|
|||
interface Builder {
|
||||
|
||||
/**
|
||||
* Configure the {@link ClientHttpConnector} to use.
|
||||
* <p>By default an instance of
|
||||
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector
|
||||
* ReactorClientHttpConnector} is created if this is not set. However a
|
||||
* shared instance may be passed instead, e.g. for use with multiple
|
||||
* {@code WebClient}'s targeting different base URIs.
|
||||
* @param connector the connector to use
|
||||
* Configure a base URI as described in {@link WebClient#create(String)
|
||||
* WebClient.create(String)}.
|
||||
* @see #defaultUriVariables(Map)
|
||||
* @see #uriBuilderFactory(UriBuilderFactory)
|
||||
*/
|
||||
Builder clientConnector(ClientHttpConnector connector);
|
||||
Builder baseUrl(String baseUrl);
|
||||
|
||||
/**
|
||||
* Configure the {@link ExchangeStrategies} to use.
|
||||
* <p>By default {@link ExchangeStrategies#withDefaults()} is used.
|
||||
* @param strategies the strategies to use
|
||||
* Configure default URI variable values that will be used when expanding
|
||||
* URI templates using a {@link Map}.
|
||||
* @param defaultUriVariables the default values to use
|
||||
* @see #baseUrl(String)
|
||||
* @see #uriBuilderFactory(UriBuilderFactory)
|
||||
*/
|
||||
Builder exchangeStrategies(ExchangeStrategies strategies);
|
||||
Builder defaultUriVariables(Map<String, ?> defaultUriVariables);
|
||||
|
||||
/**
|
||||
* Configure directly an {@link ExchangeFunction} instead of separately
|
||||
* providing a {@link ClientHttpConnector} and/or
|
||||
* {@link ExchangeStrategies}.
|
||||
* @param exchangeFunction the exchange function to use
|
||||
* Provide a pre-configured {@link UriBuilderFactory} instance. This is
|
||||
* an alternative to and effectively overrides the following:
|
||||
* <ul>
|
||||
* <li>{@link #baseUrl(String)}
|
||||
* <li>{@link #defaultUriVariables(Map)}.
|
||||
* </ul>
|
||||
* @param uriBuilderFactory the URI builder factory to use
|
||||
* @see #baseUrl(String)
|
||||
* @see #defaultUriVariables(Map)
|
||||
*/
|
||||
Builder exchangeFunction(ExchangeFunction exchangeFunction);
|
||||
Builder uriBuilderFactory(UriBuilderFactory uriBuilderFactory);
|
||||
|
||||
/**
|
||||
* Add the given header to all requests that haven't added it.
|
||||
|
|
@ -212,6 +213,41 @@ public interface WebClient {
|
|||
*/
|
||||
Builder defaultCookie(String cookieName, String... cookieValues);
|
||||
|
||||
/**
|
||||
* Configure the {@link ClientHttpConnector} to use.
|
||||
* <p>By default an instance of
|
||||
* {@link org.springframework.http.client.reactive.ReactorClientHttpConnector
|
||||
* ReactorClientHttpConnector} is created if this is not set. However a
|
||||
* shared instance may be passed instead, e.g. for use with multiple
|
||||
* {@code WebClient}'s targeting different base URIs.
|
||||
* @param connector the connector to use
|
||||
* @see #exchangeStrategies(ExchangeStrategies)
|
||||
* @see #exchangeFunction(ExchangeFunction)
|
||||
*/
|
||||
Builder clientConnector(ClientHttpConnector connector);
|
||||
|
||||
/**
|
||||
* Configure the {@link ExchangeStrategies} to use.
|
||||
* <p>By default {@link ExchangeStrategies#withDefaults()} is used.
|
||||
* @param strategies the strategies to use
|
||||
* @see #clientConnector(ClientHttpConnector)
|
||||
* @see #exchangeFunction(ExchangeFunction)
|
||||
*/
|
||||
Builder exchangeStrategies(ExchangeStrategies strategies);
|
||||
|
||||
/**
|
||||
* Provide a pre-configured {@link ExchangeFunction} instance. This is
|
||||
* an alternative to and effectively overrides the following:
|
||||
* <ul>
|
||||
* <li>{@link #clientConnector(ClientHttpConnector)}
|
||||
* <li>{@link #exchangeStrategies(ExchangeStrategies)}.
|
||||
* </ul>
|
||||
* @param exchangeFunction the exchange function to use
|
||||
* @see #clientConnector(ClientHttpConnector)
|
||||
* @see #exchangeStrategies(ExchangeStrategies)
|
||||
*/
|
||||
Builder exchangeFunction(ExchangeFunction exchangeFunction);
|
||||
|
||||
/**
|
||||
* Builder the {@link WebClient} instance.
|
||||
*/
|
||||
|
|
@ -234,14 +270,19 @@ public interface WebClient {
|
|||
* Specify the URI for the request using a URI template and URI variables.
|
||||
* If a {@link UriBuilderFactory} was configured for the client (e.g.
|
||||
* with a base URI) it will be used to expand the URI template.
|
||||
* @see #builder(String)
|
||||
*/
|
||||
HeaderSpec uri(String uri, Object... uriVariables);
|
||||
|
||||
/**
|
||||
* Specify the URI for the request using a URI template and URI variables.
|
||||
* If a {@link UriBuilderFactory} was configured for the client (e.g.
|
||||
* with a base URI) it will be used to expand the URI template.
|
||||
*/
|
||||
HeaderSpec uri(String uri, Map<String, ?> uriVariables);
|
||||
|
||||
/**
|
||||
* Build the URI for the request using the {@link UriBuilderFactory}
|
||||
* configured for this client.
|
||||
* @see #builder(String)
|
||||
*/
|
||||
HeaderSpec uri(Function<UriBuilderFactory, URI> uriFunction);
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public class DefaultWebClientTests {
|
|||
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder("/base").exchangeFunction(this.exchangeFunction);
|
||||
return WebClient.builder().baseUrl("/base").exchangeFunction(this.exchangeFunction);
|
||||
}
|
||||
|
||||
private ClientRequest<?> verifyExchange() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue