<commit_before>[[webflux-client]]
= WebClient

Spring WebFlux includes a client to perform HTTP requests with. `WebClient` has a
functional, fluent API based on Reactor, see <<web-reactive.adoc#webflux-reactive-libraries>>,
which enables declarative composition of asynchronous logic without the need to deal with
threads or concurrency. It is fully non-blocking, it supports streaming, and relies on
the same <<web-reactive.adoc#webflux-codecs, codecs>> that are also used to encode and
decode request and response content on the server side.

`WebClient` needs an HTTP client library to perform requests with. There is built-in
support for the following:

* https://github.com/reactor/reactor-netty[Reactor Netty]
* https://github.com/jetty-project/jetty-reactive-httpclient[Jetty Reactive HttpClient]
* https://hc.apache.org/index.html[Apache HttpComponents]
* Others can be plugged via `ClientHttpConnector`.




[[webflux-client-builder]]
== Configuration

The simplest way to create a `WebClient` is through one of the static factory methods:

* `WebClient.create()`
* `WebClient.create(String baseUrl)`

You can also use `WebClient.builder()` with further options:

* `uriBuilderFactory`: Customized `UriBuilderFactory` to use as a base URL.
* `defaultUriVariables`: default values to use when expanding URI templates.
* `defaultHeader`: Headers for every request.
* `defaultCookie`: Cookies for every request.
* `defaultRequest`: `Consumer` to customize every request.
* `filter`: Client filter for every request.
* `exchangeStrategies`: HTTP message reader/writer customizations.
* `clientConnector`: HTTP client library settings.

For example:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client = WebClient.builder()
			.codecs(configurer -> ... )
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val webClient = WebClient.builder()
			.codecs { configurer -> ... }
			.build()
----

Once built, a `WebClient` is immutable. However, you can clone it and build a
modified copy as follows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client1 = WebClient.builder()
			.filter(filterA).filter(filterB).build();

	WebClient client2 = client1.mutate()
			.filter(filterC).filter(filterD).build();

	// client1 has filterA, filterB

	// client2 has filterA, filterB, filterC, filterD
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client1 = WebClient.builder()
			.filter(filterA).filter(filterB).build()

	val client2 = client1.mutate()
			.filter(filterC).filter(filterD).build()

	// client1 has filterA, filterB

	// client2 has filterA, filterB, filterC, filterD
----

[[webflux-client-builder-maxinmemorysize]]
=== MaxInMemorySize

Codecs have <<web-reactive.adoc#webflux-codecs-limits,limits>> for buffering data in
memory to avoid application memory issues. By the default those are set to 256KB.
If that's not enough you'll get the following error:

----
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer
----

To change the limit for default codecs, use the following:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient webClient = WebClient.builder()
			.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val webClient = WebClient.builder()
			.codecs { configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024) }
			.build()
----



[[webflux-client-builder-reactor]]
=== Reactor Netty

To customize Reactor Netty settings, provide a pre-configured `HttpClient`:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpClient httpClient = HttpClient.create().secure(sslSpec -> ...);

	WebClient webClient = WebClient.builder()
			.clientConnector(new ReactorClientHttpConnector(httpClient))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val httpClient = HttpClient.create().secure { ... }

	val webClient = WebClient.builder()
		.clientConnector(ReactorClientHttpConnector(httpClient))
		.build()
----


[[webflux-client-builder-reactor-resources]]
==== Resources

By default, `HttpClient` participates in the global Reactor Netty resources held in
`reactor.netty.http.HttpResources`, including event loop threads and a connection pool.
This is the recommended mode, since fixed, shared resources are preferred for event loop
concurrency. In this mode global resources remain active until the process exits.

If the server is timed with the process, there is typically no need for an explicit
shutdown. However, if the server can start or stop in-process (for example, a Spring MVC
application deployed as a WAR), you can declare a Spring-managed bean of type
`ReactorResourceFactory` with `globalResources=true` (the default) to ensure that the Reactor
Netty global resources are shut down when the Spring `ApplicationContext` is closed,
as the following example shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	@Bean
	public ReactorResourceFactory reactorResourceFactory() {
		return new ReactorResourceFactory();
	}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	@Bean
	fun reactorResourceFactory() = ReactorResourceFactory()
----

You can also choose not to participate in the global Reactor Netty resources. However,
in this mode, the burden is on you to ensure that all Reactor Netty client and server
instances use shared resources, as the following example shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	@Bean
	public ReactorResourceFactory resourceFactory() {
		ReactorResourceFactory factory = new ReactorResourceFactory();
		factory.setUseGlobalResources(false); // <1>
		return factory;
	}

	@Bean
	public WebClient webClient() {

		Function<HttpClient, HttpClient> mapper = client -> {
			// Further customizations...
		};

		ClientHttpConnector connector =
				new ReactorClientHttpConnector(resourceFactory(), mapper); // <2>

		return WebClient.builder().clientConnector(connector).build(); // <3>
	}
----
<1> Create resources independent of global ones.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`.

[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	@Bean
	fun resourceFactory() = ReactorResourceFactory().apply {
		isUseGlobalResources = false // <1>
	}

	@Bean
	fun webClient(): WebClient {

		val mapper: (HttpClient) -> HttpClient = {
			// Further customizations...
		}

		val connector = ReactorClientHttpConnector(resourceFactory(), mapper) // <2>

		return WebClient.builder().clientConnector(connector).build() // <3>
	}
----
<1> Create resources independent of global ones.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`.


[[webflux-client-builder-reactor-timeout]]
==== Timeouts

To configure a connection timeout:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	import io.netty.channel.ChannelOption;

	HttpClient httpClient = HttpClient.create()
			.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);

	WebClient webClient = WebClient.builder()
			.clientConnector(new ReactorClientHttpConnector(httpClient))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	import io.netty.channel.ChannelOption

	val httpClient = HttpClient.create()
			.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);

	val webClient = WebClient.builder()
			.clientConnector(new ReactorClientHttpConnector(httpClient))
			.build();
----

To configure a read or write timeout:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	import io.netty.handler.timeout.ReadTimeoutHandler;
	import io.netty.handler.timeout.WriteTimeoutHandler;

	HttpClient httpClient = HttpClient.create()
			.doOnConnected(conn -> conn
					.addHandlerLast(new ReadTimeoutHandler(10))
					.addHandlerLast(new WriteTimeoutHandler(10)));

	// Create WebClient...

----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	import io.netty.handler.timeout.ReadTimeoutHandler
	import io.netty.handler.timeout.WriteTimeoutHandler

	val httpClient = HttpClient.create()
			.doOnConnected { conn -> conn
					.addHandlerLast(new ReadTimeoutHandler(10))
					.addHandlerLast(new WriteTimeoutHandler(10))
			}

	// Create WebClient...
----

To configure a response timeout for all requests:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpClient httpClient = HttpClient.create()
			.responseTimeout(Duration.ofSeconds(2));

	// Create WebClient...
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val httpClient = HttpClient.create()
			.responseTimeout(Duration.ofSeconds(2));

	// Create WebClient...
----

To configure a response timeout for a specific request:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient.create().get()
			.uri("https://example.org/path")
			.httpRequest(httpRequest -> {
				HttpClientRequest reactorRequest = httpRequest.getNativeRequest();
				reactorRequest.responseTimeout(Duration.ofSeconds(2));
			})
			.retrieve()
			.bodyToMono(String.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	WebClient.create().get()
			.uri("https://example.org/path")
			.httpRequest { httpRequest: ClientHttpRequest ->
				val reactorRequest = httpRequest.getNativeRequest<HttpClientRequest>()
				reactorRequest.responseTimeout(Duration.ofSeconds(2))
			}
			.retrieve()
			.bodyToMono(String::class.java)
----



[[webflux-client-builder-jetty]]
=== Jetty

The following example shows how to customize Jetty `HttpClient` settings:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpClient httpClient = new HttpClient();
	httpClient.setCookieStore(...);

	WebClient webClient = WebClient.builder()
			.clientConnector(new JettyClientHttpConnector(httpClient))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val httpClient = HttpClient()
	httpClient.cookieStore = ...

	val webClient = WebClient.builder()
			.clientConnector(new JettyClientHttpConnector(httpClient))
			.build();
----

By default, `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`),
which remain active until the process exits or `stop()` is called.

You can share resources between multiple instances of the Jetty client (and server) and
ensure that the resources are shut down when the Spring `ApplicationContext` is closed by
declaring a Spring-managed bean of type `JettyResourceFactory`, as the following example
shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	@Bean
	public JettyResourceFactory resourceFactory() {
		return new JettyResourceFactory();
	}

	@Bean
	public WebClient webClient() {

		HttpClient httpClient = new HttpClient();
		// Further customizations...
		
		ClientHttpConnector connector =
				new JettyClientHttpConnector(httpClient, resourceFactory()); <1>

		return WebClient.builder().clientConnector(connector).build(); <2>
	}
----
<1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`.

[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	@Bean
	fun resourceFactory() = JettyResourceFactory()

	@Bean
	fun webClient(): WebClient {

		val httpClient = HttpClient()
		// Further customizations...
			
		val connector = JettyClientHttpConnector(httpClient, resourceFactory()) // <1>

		return WebClient.builder().clientConnector(connector).build() // <2>
	}
----
<1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`.



[[webflux-client-builder-http-components]]
=== HttpComponents

The following example shows how to customize Apache HttpComponents `HttpClient` settings:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
	clientBuilder.setDefaultRequestConfig(...);
	CloseableHttpAsyncClient client = clientBuilder.build();
	ClientHttpConnector connector = new HttpComponentsClientHttpConnector(client);

	WebClient webClient = WebClient.builder().clientConnector(connector).build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client = HttpAsyncClients.custom().apply {
		setDefaultRequestConfig(...)
	}.build()
	val connector = HttpComponentsClientHttpConnector(client)
	val webClient = WebClient.builder().clientConnector(connector).build()
----


[[webflux-client-retrieve]]
== `retrieve()`

The `retrieve()` method can be used to declare how to extract the response. For example:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client = WebClient.create("https://example.org");

	Mono<ResponseEntity<Person>> result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.toEntity(Person.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client = WebClient.create("https://example.org")

	val result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.toEntity<Person>().awaitSingle()
----

Or to get only the body:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client = WebClient.create("https://example.org");

	Mono<Person> result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.bodyToMono(Person.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client = WebClient.create("https://example.org")

	val result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.awaitBody<Person>()
----

To get a stream of decoded objects:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	Flux<Quote> result = client.get()
			.uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM)
			.retrieve()
			.bodyToFlux(Quote.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val result = client.get()
			.uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM)
			.retrieve()
			.bodyToFlow<Quote>()
----

By default, 4xx or 5xx responses result in an `WebClientResponseException`, including
sub-classes for specific HTTP status codes. To customize the handling of error
responses, use `onStatus` handlers as follows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	Mono<Person> result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.onStatus(HttpStatus::is4xxClientError, response -> ...)
			.onStatus(HttpStatus::is5xxServerError, response -> ...)
			.bodyToMono(Person.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.onStatus(HttpStatus::is4xxClientError) { ... }
			.onStatus(HttpStatus::is5xxServerError) { ... }
			.awaitBody<Person>()
----




[[webflux-client-exchange]]
== Exchange

The `exchangeToMono()` and `exchangeToFlux()` methods (or `awaitExchange { }` and `exchangeToFlow { }` in Kotlin)
are useful for more advanced cases that require more control, such as to decode the response differently
depending on the response status:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	Mono<Object> entityMono = client.get()
		   .uri("/persons/1")
		   .accept(MediaType.APPLICATION_JSON)
		   .exchangeToMono(response -> {
			   if (response.statusCode().equals(HttpStatus.OK)) {
				   return response.bodyToMono(Person.class);
			   }
			   else if (response.statusCode().is4xxClientError()) {
				   return response.bodyToMono(ErrorContainer.class);
			   }
			   else {
				   return Mono.error(response.createException());
			   }
		   });
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
    val entity = client.get()
        .uri("/persons/1")
        .accept(MediaType.APPLICATION_JSON)
        .awaitExchange {
            if (response.statusCode() == HttpStatus.OK) {
                return response.awaitBody<Person>();
            }
            else if (response.statusCode().is4xxClientError) {
                return response.awaitBody<ErrorContainer>();
            }
            else {
                return response.createExceptionAndAwait();
            }
        }
----

When using the above, after the returned `Mono` or `Flux` completes, the response body
is checked and if not consumed it is released to prevent memory and connection leaks.
Therefore the response cannot be decoded further downstream. It is up to the provided
function to declare how to decode the response if needed.




[[webflux-client-body]]
== Request Body

The request body can be encoded from any asynchronous type handled by `ReactiveAdapterRegistry`,
like `Mono` or Kotlin Coroutines `Deferred` as the following example shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]<commit_msg>Fix exchangeToMono sample in reference<commit_after>[[webflux-client]]
= WebClient

Spring WebFlux includes a client to perform HTTP requests with. `WebClient` has a
functional, fluent API based on Reactor, see <<web-reactive.adoc#webflux-reactive-libraries>>,
which enables declarative composition of asynchronous logic without the need to deal with
threads or concurrency. It is fully non-blocking, it supports streaming, and relies on
the same <<web-reactive.adoc#webflux-codecs, codecs>> that are also used to encode and
decode request and response content on the server side.

`WebClient` needs an HTTP client library to perform requests with. There is built-in
support for the following:

* https://github.com/reactor/reactor-netty[Reactor Netty]
* https://github.com/jetty-project/jetty-reactive-httpclient[Jetty Reactive HttpClient]
* https://hc.apache.org/index.html[Apache HttpComponents]
* Others can be plugged via `ClientHttpConnector`.




[[webflux-client-builder]]
== Configuration

The simplest way to create a `WebClient` is through one of the static factory methods:

* `WebClient.create()`
* `WebClient.create(String baseUrl)`

You can also use `WebClient.builder()` with further options:

* `uriBuilderFactory`: Customized `UriBuilderFactory` to use as a base URL.
* `defaultUriVariables`: default values to use when expanding URI templates.
* `defaultHeader`: Headers for every request.
* `defaultCookie`: Cookies for every request.
* `defaultRequest`: `Consumer` to customize every request.
* `filter`: Client filter for every request.
* `exchangeStrategies`: HTTP message reader/writer customizations.
* `clientConnector`: HTTP client library settings.

For example:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client = WebClient.builder()
			.codecs(configurer -> ... )
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val webClient = WebClient.builder()
			.codecs { configurer -> ... }
			.build()
----

Once built, a `WebClient` is immutable. However, you can clone it and build a
modified copy as follows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client1 = WebClient.builder()
			.filter(filterA).filter(filterB).build();

	WebClient client2 = client1.mutate()
			.filter(filterC).filter(filterD).build();

	// client1 has filterA, filterB

	// client2 has filterA, filterB, filterC, filterD
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client1 = WebClient.builder()
			.filter(filterA).filter(filterB).build()

	val client2 = client1.mutate()
			.filter(filterC).filter(filterD).build()

	// client1 has filterA, filterB

	// client2 has filterA, filterB, filterC, filterD
----

[[webflux-client-builder-maxinmemorysize]]
=== MaxInMemorySize

Codecs have <<web-reactive.adoc#webflux-codecs-limits,limits>> for buffering data in
memory to avoid application memory issues. By the default those are set to 256KB.
If that's not enough you'll get the following error:

----
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer
----

To change the limit for default codecs, use the following:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient webClient = WebClient.builder()
			.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val webClient = WebClient.builder()
			.codecs { configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024) }
			.build()
----



[[webflux-client-builder-reactor]]
=== Reactor Netty

To customize Reactor Netty settings, provide a pre-configured `HttpClient`:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpClient httpClient = HttpClient.create().secure(sslSpec -> ...);

	WebClient webClient = WebClient.builder()
			.clientConnector(new ReactorClientHttpConnector(httpClient))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val httpClient = HttpClient.create().secure { ... }

	val webClient = WebClient.builder()
		.clientConnector(ReactorClientHttpConnector(httpClient))
		.build()
----


[[webflux-client-builder-reactor-resources]]
==== Resources

By default, `HttpClient` participates in the global Reactor Netty resources held in
`reactor.netty.http.HttpResources`, including event loop threads and a connection pool.
This is the recommended mode, since fixed, shared resources are preferred for event loop
concurrency. In this mode global resources remain active until the process exits.

If the server is timed with the process, there is typically no need for an explicit
shutdown. However, if the server can start or stop in-process (for example, a Spring MVC
application deployed as a WAR), you can declare a Spring-managed bean of type
`ReactorResourceFactory` with `globalResources=true` (the default) to ensure that the Reactor
Netty global resources are shut down when the Spring `ApplicationContext` is closed,
as the following example shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	@Bean
	public ReactorResourceFactory reactorResourceFactory() {
		return new ReactorResourceFactory();
	}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	@Bean
	fun reactorResourceFactory() = ReactorResourceFactory()
----

You can also choose not to participate in the global Reactor Netty resources. However,
in this mode, the burden is on you to ensure that all Reactor Netty client and server
instances use shared resources, as the following example shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	@Bean
	public ReactorResourceFactory resourceFactory() {
		ReactorResourceFactory factory = new ReactorResourceFactory();
		factory.setUseGlobalResources(false); // <1>
		return factory;
	}

	@Bean
	public WebClient webClient() {

		Function<HttpClient, HttpClient> mapper = client -> {
			// Further customizations...
		};

		ClientHttpConnector connector =
				new ReactorClientHttpConnector(resourceFactory(), mapper); // <2>

		return WebClient.builder().clientConnector(connector).build(); // <3>
	}
----
<1> Create resources independent of global ones.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`.

[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	@Bean
	fun resourceFactory() = ReactorResourceFactory().apply {
		isUseGlobalResources = false // <1>
	}

	@Bean
	fun webClient(): WebClient {

		val mapper: (HttpClient) -> HttpClient = {
			// Further customizations...
		}

		val connector = ReactorClientHttpConnector(resourceFactory(), mapper) // <2>

		return WebClient.builder().clientConnector(connector).build() // <3>
	}
----
<1> Create resources independent of global ones.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`.


[[webflux-client-builder-reactor-timeout]]
==== Timeouts

To configure a connection timeout:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	import io.netty.channel.ChannelOption;

	HttpClient httpClient = HttpClient.create()
			.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);

	WebClient webClient = WebClient.builder()
			.clientConnector(new ReactorClientHttpConnector(httpClient))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	import io.netty.channel.ChannelOption

	val httpClient = HttpClient.create()
			.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);

	val webClient = WebClient.builder()
			.clientConnector(new ReactorClientHttpConnector(httpClient))
			.build();
----

To configure a read or write timeout:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	import io.netty.handler.timeout.ReadTimeoutHandler;
	import io.netty.handler.timeout.WriteTimeoutHandler;

	HttpClient httpClient = HttpClient.create()
			.doOnConnected(conn -> conn
					.addHandlerLast(new ReadTimeoutHandler(10))
					.addHandlerLast(new WriteTimeoutHandler(10)));

	// Create WebClient...

----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	import io.netty.handler.timeout.ReadTimeoutHandler
	import io.netty.handler.timeout.WriteTimeoutHandler

	val httpClient = HttpClient.create()
			.doOnConnected { conn -> conn
					.addHandlerLast(new ReadTimeoutHandler(10))
					.addHandlerLast(new WriteTimeoutHandler(10))
			}

	// Create WebClient...
----

To configure a response timeout for all requests:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpClient httpClient = HttpClient.create()
			.responseTimeout(Duration.ofSeconds(2));

	// Create WebClient...
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val httpClient = HttpClient.create()
			.responseTimeout(Duration.ofSeconds(2));

	// Create WebClient...
----

To configure a response timeout for a specific request:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient.create().get()
			.uri("https://example.org/path")
			.httpRequest(httpRequest -> {
				HttpClientRequest reactorRequest = httpRequest.getNativeRequest();
				reactorRequest.responseTimeout(Duration.ofSeconds(2));
			})
			.retrieve()
			.bodyToMono(String.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	WebClient.create().get()
			.uri("https://example.org/path")
			.httpRequest { httpRequest: ClientHttpRequest ->
				val reactorRequest = httpRequest.getNativeRequest<HttpClientRequest>()
				reactorRequest.responseTimeout(Duration.ofSeconds(2))
			}
			.retrieve()
			.bodyToMono(String::class.java)
----



[[webflux-client-builder-jetty]]
=== Jetty

The following example shows how to customize Jetty `HttpClient` settings:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpClient httpClient = new HttpClient();
	httpClient.setCookieStore(...);

	WebClient webClient = WebClient.builder()
			.clientConnector(new JettyClientHttpConnector(httpClient))
			.build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val httpClient = HttpClient()
	httpClient.cookieStore = ...

	val webClient = WebClient.builder()
			.clientConnector(new JettyClientHttpConnector(httpClient))
			.build();
----

By default, `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`),
which remain active until the process exits or `stop()` is called.

You can share resources between multiple instances of the Jetty client (and server) and
ensure that the resources are shut down when the Spring `ApplicationContext` is closed by
declaring a Spring-managed bean of type `JettyResourceFactory`, as the following example
shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	@Bean
	public JettyResourceFactory resourceFactory() {
		return new JettyResourceFactory();
	}

	@Bean
	public WebClient webClient() {

		HttpClient httpClient = new HttpClient();
		// Further customizations...
		
		ClientHttpConnector connector =
				new JettyClientHttpConnector(httpClient, resourceFactory()); <1>

		return WebClient.builder().clientConnector(connector).build(); <2>
	}
----
<1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`.

[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	@Bean
	fun resourceFactory() = JettyResourceFactory()

	@Bean
	fun webClient(): WebClient {

		val httpClient = HttpClient()
		// Further customizations...
			
		val connector = JettyClientHttpConnector(httpClient, resourceFactory()) // <1>

		return WebClient.builder().clientConnector(connector).build() // <2>
	}
----
<1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`.



[[webflux-client-builder-http-components]]
=== HttpComponents

The following example shows how to customize Apache HttpComponents `HttpClient` settings:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
	clientBuilder.setDefaultRequestConfig(...);
	CloseableHttpAsyncClient client = clientBuilder.build();
	ClientHttpConnector connector = new HttpComponentsClientHttpConnector(client);

	WebClient webClient = WebClient.builder().clientConnector(connector).build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client = HttpAsyncClients.custom().apply {
		setDefaultRequestConfig(...)
	}.build()
	val connector = HttpComponentsClientHttpConnector(client)
	val webClient = WebClient.builder().clientConnector(connector).build()
----


[[webflux-client-retrieve]]
== `retrieve()`

The `retrieve()` method can be used to declare how to extract the response. For example:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client = WebClient.create("https://example.org");

	Mono<ResponseEntity<Person>> result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.toEntity(Person.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client = WebClient.create("https://example.org")

	val result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.toEntity<Person>().awaitSingle()
----

Or to get only the body:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	WebClient client = WebClient.create("https://example.org");

	Mono<Person> result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.bodyToMono(Person.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val client = WebClient.create("https://example.org")

	val result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.awaitBody<Person>()
----

To get a stream of decoded objects:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	Flux<Quote> result = client.get()
			.uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM)
			.retrieve()
			.bodyToFlux(Quote.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val result = client.get()
			.uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM)
			.retrieve()
			.bodyToFlow<Quote>()
----

By default, 4xx or 5xx responses result in an `WebClientResponseException`, including
sub-classes for specific HTTP status codes. To customize the handling of error
responses, use `onStatus` handlers as follows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	Mono<Person> result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.onStatus(HttpStatus::is4xxClientError, response -> ...)
			.onStatus(HttpStatus::is5xxServerError, response -> ...)
			.bodyToMono(Person.class);
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
	val result = client.get()
			.uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
			.retrieve()
			.onStatus(HttpStatus::is4xxClientError) { ... }
			.onStatus(HttpStatus::is5xxServerError) { ... }
			.awaitBody<Person>()
----




[[webflux-client-exchange]]
== Exchange

The `exchangeToMono()` and `exchangeToFlux()` methods (or `awaitExchange { }` and `exchangeToFlow { }` in Kotlin)
are useful for more advanced cases that require more control, such as to decode the response differently
depending on the response status:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
	Mono<Object> entityMono = client.get()
			.uri("/persons/1")
			.accept(MediaType.APPLICATION_JSON)
			.exchangeToMono(response -> {
				if (response.statusCode().equals(HttpStatus.OK)) {
					return response.bodyToMono(Person.class);
				}
				else if (response.statusCode().is4xxClientError()) {
					// Suppress error status code
					return response.bodyToMono(ErrorContainer.class);
				}
				else {
					// Turn to error
					return response.createException().flatMap(Mono::error);
				}
			});
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val entity = client.get()
  .uri("/persons/1")
  .accept(MediaType.APPLICATION_JSON)
  .awaitExchange {
		if (response.statusCode() == HttpStatus.OK) {
			 return response.awaitBody<Person>()
		}
		else if (response.statusCode().is4xxClientError) {
			 return response.awaitBody<ErrorContainer>()
		}
		else {
			 throw response.createExceptionAndAwait()
		}
  }
----

When using the above, after the returned `Mono` or `Flux` completes, the response body
is checked and if not consumed it is released to prevent memory and connection leaks.
Therefore the response cannot be decoded further downstream. It is up to the provided
function to declare how to decode the response if needed.




[[webflux-client-body]]
== Request Body

The request body can be encoded from any asynchronous type handled by `ReactiveAdapterRegistry`,
like `Mono` or Kotlin Coroutines `Deferred` as the following example shows:

[source,java,indent=0,subs="verbatim,quotes",role="primary"]
{'fraction_non_alphanumeric': 0.14070252034133757, 'fraction_numerical': 0.006804071102543022, 'mean_word_length': 4.705920414105467, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 111, 'https://': 18, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2757068', 'n_tokens_mistral': 11550, 'n_tokens_neox': 10611, 'n_words': 2604}