001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.reactive.function.client;
018
019import java.net.URI;
020import java.nio.charset.Charset;
021import java.time.ZonedDateTime;
022import java.util.List;
023import java.util.Map;
024import java.util.function.Consumer;
025import java.util.function.Function;
026import java.util.function.IntPredicate;
027import java.util.function.Predicate;
028
029import org.reactivestreams.Publisher;
030import reactor.core.publisher.Flux;
031import reactor.core.publisher.Mono;
032
033import org.springframework.core.ParameterizedTypeReference;
034import org.springframework.core.ReactiveAdapterRegistry;
035import org.springframework.http.HttpHeaders;
036import org.springframework.http.HttpMethod;
037import org.springframework.http.HttpStatus;
038import org.springframework.http.MediaType;
039import org.springframework.http.ResponseEntity;
040import org.springframework.http.client.reactive.ClientHttpConnector;
041import org.springframework.http.client.reactive.ClientHttpRequest;
042import org.springframework.http.codec.ClientCodecConfigurer;
043import org.springframework.util.MultiValueMap;
044import org.springframework.web.reactive.function.BodyInserter;
045import org.springframework.web.reactive.function.BodyInserters;
046import org.springframework.web.util.DefaultUriBuilderFactory;
047import org.springframework.web.util.UriBuilder;
048import org.springframework.web.util.UriBuilderFactory;
049
050/**
051 * Non-blocking, reactive client to perform HTTP requests, exposing a fluent,
052 * reactive API over underlying HTTP client libraries such as Reactor Netty.
053 *
054 * <p>Use static factory methods {@link #create()} or {@link #create(String)},
055 * or {@link WebClient#builder()} to prepare an instance.
056 *
057 * <p>For examples with a response body see:
058 * <ul>
059 * <li>{@link RequestHeadersSpec#retrieve() retrieve()}
060 * <li>{@link RequestHeadersSpec#exchange() exchange()}
061 * </ul>
062 * <p>For examples with a request body see:
063 * <ul>
064 * <li>{@link RequestBodySpec#bodyValue(Object) bodyValue(Object)}
065 * <li>{@link RequestBodySpec#body(Publisher, Class) body(Publisher,Class)}
066 * </ul>
067 *
068 * @author Rossen Stoyanchev
069 * @author Arjen Poutsma
070 * @author Sebastien Deleuze
071 * @author Brian Clozel
072 * @since 5.0
073 */
074public interface WebClient {
075
076        /**
077         * Start building an HTTP GET request.
078         * @return a spec for specifying the target URL
079         */
080        RequestHeadersUriSpec<?> get();
081
082        /**
083         * Start building an HTTP HEAD request.
084         * @return a spec for specifying the target URL
085         */
086        RequestHeadersUriSpec<?> head();
087
088        /**
089         * Start building an HTTP POST request.
090         * @return a spec for specifying the target URL
091         */
092        RequestBodyUriSpec post();
093
094        /**
095         * Start building an HTTP PUT request.
096         * @return a spec for specifying the target URL
097         */
098        RequestBodyUriSpec put();
099
100        /**
101         * Start building an HTTP PATCH request.
102         * @return a spec for specifying the target URL
103         */
104        RequestBodyUriSpec patch();
105
106        /**
107         * Start building an HTTP DELETE request.
108         * @return a spec for specifying the target URL
109         */
110        RequestHeadersUriSpec<?> delete();
111
112        /**
113         * Start building an HTTP OPTIONS request.
114         * @return a spec for specifying the target URL
115         */
116        RequestHeadersUriSpec<?> options();
117
118        /**
119         * Start building a request for the given {@code HttpMethod}.
120         * @return a spec for specifying the target URL
121         */
122        RequestBodyUriSpec method(HttpMethod method);
123
124
125        /**
126         * Return a builder to create a new {@code WebClient} whose settings are
127         * replicated from the current {@code WebClient}.
128         */
129        Builder mutate();
130
131
132        // Static, factory methods
133
134        /**
135         * Create a new {@code WebClient} with Reactor Netty by default.
136         * @see #create(String)
137         * @see #builder()
138         */
139        static WebClient create() {
140                return new DefaultWebClientBuilder().build();
141        }
142
143        /**
144         * Variant of {@link #create()} that accepts a default base URL. For more
145         * details see {@link Builder#baseUrl(String) Builder.baseUrl(String)}.
146         * @param baseUrl the base URI for all requests
147         * @see #builder()
148         */
149        static WebClient create(String baseUrl) {
150                return new DefaultWebClientBuilder().baseUrl(baseUrl).build();
151        }
152
153        /**
154         * Obtain a {@code WebClient} builder.
155         */
156        static WebClient.Builder builder() {
157                return new DefaultWebClientBuilder();
158        }
159
160
161        /**
162         * A mutable builder for creating a {@link WebClient}.
163         */
164        interface Builder {
165
166                /**
167                 * Configure a base URL for requests. Effectively a shortcut for:
168                 * <p>
169                 * <pre class="code">
170                 * String baseUrl = "https://abc.go.com/v1";
171                 * DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
172                 * WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
173                 * </pre>
174                 * <p>The {@code DefaultUriBuilderFactory} is used to prepare the URL
175                 * for every request with the given base URL, unless the URL request
176                 * for a given URL is absolute in which case the base URL is ignored.
177                 * <p><strong>Note:</strong> this method is mutually exclusive with
178                 * {@link #uriBuilderFactory(UriBuilderFactory)}. If both are used, the
179                 * baseUrl value provided here will be ignored.
180                 * @see DefaultUriBuilderFactory#DefaultUriBuilderFactory(String)
181                 * @see #uriBuilderFactory(UriBuilderFactory)
182                 */
183                Builder baseUrl(String baseUrl);
184
185                /**
186                 * Configure default URI variable values that will be used when expanding
187                 * URI templates using a {@link Map}.
188                 * @param defaultUriVariables the default values to use
189                 * @see #baseUrl(String)
190                 * @see #uriBuilderFactory(UriBuilderFactory)
191                 */
192                /**
193                 * Configure default URL variable values to use when expanding URI
194                 * templates with a {@link Map}. Effectively a shortcut for:
195                 * <p>
196                 * <pre class="code">
197                 * Map&lt;String, ?&gt; defaultVars = ...;
198                 * DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();
199                 * factory.setDefaultVariables(defaultVars);
200                 * WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
201                 * </pre>
202                 * <p><strong>Note:</strong> this method is mutually exclusive with
203                 * {@link #uriBuilderFactory(UriBuilderFactory)}. If both are used, the
204                 * defaultUriVariables value provided here will be ignored.
205                 * @see DefaultUriBuilderFactory#setDefaultUriVariables(Map)
206                 * @see #uriBuilderFactory(UriBuilderFactory)
207                 */
208                Builder defaultUriVariables(Map<String, ?> defaultUriVariables);
209
210                /**
211                 * Provide a pre-configured {@link UriBuilderFactory} instance. This is
212                 * an alternative to, and effectively overrides the following shortcut
213                 * properties:
214                 * <ul>
215                 * <li>{@link #baseUrl(String)}
216                 * <li>{@link #defaultUriVariables(Map)}.
217                 * </ul>
218                 * @param uriBuilderFactory the URI builder factory to use
219                 * @see #baseUrl(String)
220                 * @see #defaultUriVariables(Map)
221                 */
222                Builder uriBuilderFactory(UriBuilderFactory uriBuilderFactory);
223
224                /**
225                 * Global option to specify a header to be added to every request,
226                 * if the request does not already contain such a header.
227                 * @param header the header name
228                 * @param values the header values
229                 */
230                Builder defaultHeader(String header, String... values);
231
232                /**
233                 * Provides access to every {@link #defaultHeader(String, String...)}
234                 * declared so far with the possibility to add, replace, or remove.
235                 * @param headersConsumer the consumer
236                 */
237                Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer);
238
239                /**
240                 * Global option to specify a cookie to be added to every request,
241                 * if the request does not already contain such a cookie.
242                 * @param cookie the cookie name
243                 * @param values the cookie values
244                 */
245                Builder defaultCookie(String cookie, String... values);
246
247                /**
248                 * Provides access to every {@link #defaultCookie(String, String...)}
249                 * declared so far with the possibility to add, replace, or remove.
250                 * @param cookiesConsumer a function that consumes the cookies map
251                 */
252                Builder defaultCookies(Consumer<MultiValueMap<String, String>> cookiesConsumer);
253
254                /**
255                 * Provide a consumer to modify every request being built just before the
256                 * call to {@link RequestHeadersSpec#exchange() exchange()}.
257                 * @param defaultRequest the consumer to use for modifying requests
258                 * @since 5.1
259                 */
260                Builder defaultRequest(Consumer<RequestHeadersSpec<?>> defaultRequest);
261
262                /**
263                 * Add the given filter to the end of the filter chain.
264                 * @param filter the filter to be added to the chain
265                 */
266                Builder filter(ExchangeFilterFunction filter);
267
268                /**
269                 * Manipulate the filters with the given consumer. The list provided to
270                 * the consumer is "live", so that the consumer can be used to remove
271                 * filters, change ordering, etc.
272                 * @param filtersConsumer a function that consumes the filter list
273                 * @return this builder
274                 */
275                Builder filters(Consumer<List<ExchangeFilterFunction>> filtersConsumer);
276
277                /**
278                 * Configure the {@link ClientHttpConnector} to use. This is useful for
279                 * plugging in and/or customizing options of the underlying HTTP client
280                 * library (e.g. SSL).
281                 * <p>By default this is set to
282                 * {@link org.springframework.http.client.reactive.ReactorClientHttpConnector
283                 * ReactorClientHttpConnector}.
284                 * @param connector the connector to use
285                 */
286                Builder clientConnector(ClientHttpConnector connector);
287
288                /**
289                 * Configure the codecs for the {@code WebClient} in the
290                 * {@link #exchangeStrategies(ExchangeStrategies) underlying}
291                 * {@code ExchangeStrategies}.
292                 * @param configurer the configurer to apply
293                 * @since 5.1.13
294                 */
295                Builder codecs(Consumer<ClientCodecConfigurer> configurer);
296
297                /**
298                 * Configure the {@link ExchangeStrategies} to use.
299                 * <p>For most cases, prefer using {@link #codecs(Consumer)} which allows
300                 * customizing the codecs in the {@code ExchangeStrategies} rather than
301                 * replace them. That ensures multiple parties can contribute to codecs
302                 * configuration.
303                 * <p>By default this is set to {@link ExchangeStrategies#withDefaults()}.
304                 * @param strategies the strategies to use
305                 */
306                Builder exchangeStrategies(ExchangeStrategies strategies);
307
308                /**
309                 * Customize the strategies configured via
310                 * {@link #exchangeStrategies(ExchangeStrategies)}. This method is
311                 * designed for use in scenarios where multiple parties wish to update
312                 * the {@code ExchangeStrategies}.
313                 * @deprecated as of 5.1.13 in favor of {@link #codecs(Consumer)}
314                 */
315                @Deprecated
316                Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer);
317
318                /**
319                 * Provide an {@link ExchangeFunction} pre-configured with
320                 * {@link ClientHttpConnector} and {@link ExchangeStrategies}.
321                 * <p>This is an alternative to, and effectively overrides
322                 * {@link #clientConnector}, and
323                 * {@link #exchangeStrategies(ExchangeStrategies)}.
324                 * @param exchangeFunction the exchange function to use
325                 */
326                Builder exchangeFunction(ExchangeFunction exchangeFunction);
327
328                /**
329                 * Apply the given {@code Consumer} to this builder instance.
330                 * <p>This can be useful for applying pre-packaged customizations.
331                 * @param builderConsumer the consumer to apply
332                 */
333                Builder apply(Consumer<Builder> builderConsumer);
334
335                /**
336                 * Clone this {@code WebClient.Builder}.
337                 */
338                Builder clone();
339
340                /**
341                 * Builder the {@link WebClient} instance.
342                 */
343                WebClient build();
344        }
345
346
347        /**
348         * Contract for specifying the URI for a request.
349         * @param <S> a self reference to the spec type
350         */
351        interface UriSpec<S extends RequestHeadersSpec<?>> {
352
353                /**
354                 * Specify the URI using an absolute, fully constructed {@link URI}.
355                 */
356                S uri(URI uri);
357
358                /**
359                 * Specify the URI for the request using a URI template and URI variables.
360                 * If a {@link UriBuilderFactory} was configured for the client (e.g.
361                 * with a base URI) it will be used to expand the URI template.
362                 */
363                S uri(String uri, Object... uriVariables);
364
365                /**
366                 * Specify the URI for the request using a URI template and URI variables.
367                 * If a {@link UriBuilderFactory} was configured for the client (e.g.
368                 * with a base URI) it will be used to expand the URI template.
369                 */
370                S uri(String uri, Map<String, ?> uriVariables);
371
372                /**
373                 * Specify the URI starting with a URI template and finishing off with a
374                 * {@link UriBuilder} created from the template.
375                 * @since 5.2
376                 */
377                S uri(String uri, Function<UriBuilder, URI> uriFunction);
378
379                /**
380                 * Specify the URI by through a {@link UriBuilder}.
381                 * @see #uri(String, Function)
382                 */
383                S uri(Function<UriBuilder, URI> uriFunction);
384        }
385
386
387        /**
388         * Contract for specifying request headers leading up to the exchange.
389         * @param <S> a self reference to the spec type
390         */
391        interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {
392
393                /**
394                 * Set the list of acceptable {@linkplain MediaType media types}, as
395                 * specified by the {@code Accept} header.
396                 * @param acceptableMediaTypes the acceptable media types
397                 * @return this builder
398                 */
399                S accept(MediaType... acceptableMediaTypes);
400
401                /**
402                 * Set the list of acceptable {@linkplain Charset charsets}, as specified
403                 * by the {@code Accept-Charset} header.
404                 * @param acceptableCharsets the acceptable charsets
405                 * @return this builder
406                 */
407                S acceptCharset(Charset... acceptableCharsets);
408
409                /**
410                 * Add a cookie with the given name and value.
411                 * @param name the cookie name
412                 * @param value the cookie value
413                 * @return this builder
414                 */
415                S cookie(String name, String value);
416
417                /**
418                 * Provides access to every cookie declared so far with the possibility
419                 * to add, replace, or remove values.
420                 * @param cookiesConsumer the consumer to provide access to
421                 * @return this builder
422                 */
423                S cookies(Consumer<MultiValueMap<String, String>> cookiesConsumer);
424
425                /**
426                 * Set the value of the {@code If-Modified-Since} header.
427                 * <p>The date should be specified as the number of milliseconds since
428                 * January 1, 1970 GMT.
429                 * @param ifModifiedSince the new value of the header
430                 * @return this builder
431                 */
432                S ifModifiedSince(ZonedDateTime ifModifiedSince);
433
434                /**
435                 * Set the values of the {@code If-None-Match} header.
436                 * @param ifNoneMatches the new value of the header
437                 * @return this builder
438                 */
439                S ifNoneMatch(String... ifNoneMatches);
440
441                /**
442                 * Add the given, single header value under the given name.
443                 * @param headerName  the header name
444                 * @param headerValues the header value(s)
445                 * @return this builder
446                 */
447                S header(String headerName, String... headerValues);
448
449                /**
450                 * Provides access to every header declared so far with the possibility
451                 * to add, replace, or remove values.
452                 * @param headersConsumer the consumer to provide access to
453                 * @return this builder
454                 */
455                S headers(Consumer<HttpHeaders> headersConsumer);
456
457                /**
458                 * Set the attribute with the given name to the given value.
459                 * @param name the name of the attribute to add
460                 * @param value the value of the attribute to add
461                 * @return this builder
462                 */
463                S attribute(String name, Object value);
464
465                /**
466                 * Provides access to every attribute declared so far with the
467                 * possibility to add, replace, or remove values.
468                 * @param attributesConsumer the consumer to provide access to
469                 * @return this builder
470                 */
471                S attributes(Consumer<Map<String, Object>> attributesConsumer);
472
473                /**
474                 * Perform the HTTP request and retrieve the response body:
475                 * <p><pre>
476                 * Mono&lt;Person&gt; bodyMono = client.get()
477                 *     .uri("/persons/1")
478                 *     .accept(MediaType.APPLICATION_JSON)
479                 *     .retrieve()
480                 *     .bodyToMono(Person.class);
481                 * </pre>
482                 * <p>This method is a shortcut to using {@link #exchange()} and
483                 * decoding the response body through {@link ClientResponse}.
484                 * @return {@code ResponseSpec} to specify how to decode the body
485                 * @see #exchange()
486                 */
487                ResponseSpec retrieve();
488
489                /**
490                 * Perform the HTTP request and return a {@link ClientResponse} with the
491                 * response status and headers. You can then use methods of the response
492                 * to consume the body:
493                 * <p><pre>
494                 * Mono&lt;Person&gt; mono = client.get()
495                 *     .uri("/persons/1")
496                 *     .accept(MediaType.APPLICATION_JSON)
497                 *     .exchange()
498                 *     .flatMap(response -&gt; response.bodyToMono(Person.class));
499                 *
500                 * Flux&lt;Person&gt; flux = client.get()
501                 *     .uri("/persons")
502                 *     .accept(MediaType.APPLICATION_STREAM_JSON)
503                 *     .exchange()
504                 *     .flatMapMany(response -&gt; response.bodyToFlux(Person.class));
505                 * </pre>
506                 * <p><strong>NOTE:</strong> Unlike {@link #retrieve()}, when using
507                 * {@code exchange()}, it is the responsibility of the application to
508                 * consume any response content regardless of the scenario (success,
509                 * error, unexpected data, etc). Not doing so can cause a memory leak.
510                 * See {@link ClientResponse} for a list of all the available options
511                 * for consuming the body. Generally prefer using {@link #retrieve()}
512                 * unless you have a good reason to use {@code exchange()} which does
513                 * allow to check the response status and headers before deciding how or
514                 * if to consume the response.
515                 * @return a {@code Mono} for the response
516                 * @see #retrieve()
517                 */
518                Mono<ClientResponse> exchange();
519        }
520
521
522        /**
523         * Contract for specifying request headers and body leading up to the exchange.
524         */
525        interface RequestBodySpec extends RequestHeadersSpec<RequestBodySpec> {
526
527                /**
528                 * Set the length of the body in bytes, as specified by the
529                 * {@code Content-Length} header.
530                 * @param contentLength the content length
531                 * @return this builder
532                 * @see HttpHeaders#setContentLength(long)
533                 */
534                RequestBodySpec contentLength(long contentLength);
535
536                /**
537                 * Set the {@linkplain MediaType media type} of the body, as specified
538                 * by the {@code Content-Type} header.
539                 * @param contentType the content type
540                 * @return this builder
541                 * @see HttpHeaders#setContentType(MediaType)
542                 */
543                RequestBodySpec contentType(MediaType contentType);
544
545                /**
546                 * Shortcut for {@link #body(BodyInserter)} with a
547                 * {@linkplain BodyInserters#fromValue value inserter}.
548                 * For example:
549                 * <p><pre class="code">
550                 * Person person = ... ;
551                 *
552                 * Mono&lt;Void&gt; result = client.post()
553                 *     .uri("/persons/{id}", id)
554                 *     .contentType(MediaType.APPLICATION_JSON)
555                 *     .bodyValue(person)
556                 *     .retrieve()
557                 *     .bodyToMono(Void.class);
558                 * </pre>
559                 * <p>For multipart requests consider providing
560                 * {@link org.springframework.util.MultiValueMap MultiValueMap} prepared
561                 * with {@link org.springframework.http.client.MultipartBodyBuilder
562                 * MultipartBodyBuilder}.
563                 * @param body the value to write to the request body
564                 * @return this builder
565                 * @throws IllegalArgumentException if {@code body} is a
566                 * {@link Publisher} or producer known to {@link ReactiveAdapterRegistry}
567                 * @since 5.2
568                 */
569                RequestHeadersSpec<?> bodyValue(Object body);
570
571                /**
572                 * Shortcut for {@link #body(BodyInserter)} with a
573                 * {@linkplain BodyInserters#fromPublisher Publisher inserter}.
574                 * For example:
575                 * <p><pre>
576                 * Mono&lt;Person&gt; personMono = ... ;
577                 *
578                 * Mono&lt;Void&gt; result = client.post()
579                 *     .uri("/persons/{id}", id)
580                 *     .contentType(MediaType.APPLICATION_JSON)
581                 *     .body(personMono, Person.class)
582                 *     .retrieve()
583                 *     .bodyToMono(Void.class);
584                 * </pre>
585                 * @param publisher the {@code Publisher} to write to the request
586                 * @param elementClass the type of elements published
587                 * @param <T> the type of the elements contained in the publisher
588                 * @param <P> the type of the {@code Publisher}
589                 * @return this builder
590                 */
591                <T, P extends Publisher<T>> RequestHeadersSpec<?> body(P publisher, Class<T> elementClass);
592
593                /**
594                 * Variant of {@link #body(Publisher, Class)} that allows providing
595                 * element type information with generics.
596                 * @param publisher the {@code Publisher} to write to the request
597                 * @param elementTypeRef the type of elements published
598                 * @param <T> the type of the elements contained in the publisher
599                 * @param <P> the type of the {@code Publisher}
600                 * @return this builder
601                 */
602                <T, P extends Publisher<T>> RequestHeadersSpec<?> body(P publisher,
603                                ParameterizedTypeReference<T> elementTypeRef);
604
605                /**
606                 * Variant of {@link #body(Publisher, Class)} that allows using any
607                 * producer that can be resolved to {@link Publisher} via
608                 * {@link ReactiveAdapterRegistry}.
609                 * @param producer the producer to write to the request
610                 * @param elementClass the type of elements produced
611                 * @return this builder
612                 * @since 5.2
613                 */
614                RequestHeadersSpec<?> body(Object producer, Class<?> elementClass);
615
616                /**
617                 * Variant of {@link #body(Publisher, ParameterizedTypeReference)} that
618                 * allows using any producer that can be resolved to {@link Publisher}
619                 * via {@link ReactiveAdapterRegistry}.
620                 * @param producer the producer to write to the request
621                 * @param elementTypeRef the type of elements produced
622                 * @return this builder
623                 * @since 5.2
624                 */
625                RequestHeadersSpec<?> body(Object producer, ParameterizedTypeReference<?> elementTypeRef);
626
627                /**
628                 * Set the body of the request using the given body inserter.
629                 * See {@link BodyInserters} for built-in {@link BodyInserter} implementations.
630                 * @param inserter the body inserter to use for the request body
631                 * @return this builder
632                 * @see org.springframework.web.reactive.function.BodyInserters
633                 */
634                RequestHeadersSpec<?> body(BodyInserter<?, ? super ClientHttpRequest> inserter);
635
636                /**
637                 * Shortcut for {@link #body(BodyInserter)} with a
638                 * {@linkplain BodyInserters#fromValue value inserter}.
639                 * As of 5.2 this method delegates to {@link #bodyValue(Object)}.
640                 * @deprecated as of Spring Framework 5.2 in favor of {@link #bodyValue(Object)}
641                 */
642                @Deprecated
643                RequestHeadersSpec<?> syncBody(Object body);
644        }
645
646
647        /**
648         * Contract for specifying response operations following the exchange.
649         */
650        interface ResponseSpec {
651
652                /**
653                 * Provide a function to map specific error status codes to an error
654                 * signal to be propagated downstream instead of the response.
655                 * <p>By default, if there are no matching status handlers, responses
656                 * with status codes >= 400 are mapped to
657                 * {@link WebClientResponseException} which is created with
658                 * {@link ClientResponse#createException()}.
659                 * <p>To suppress the treatment of a status code as an error and process
660                 * it as a normal response, return {@code Mono.empty()} from the function.
661                 * The response will then propagate downstream to be processed.
662                 * <p>To ignore an error response completely, and propagate neither
663                 * response nor error, use a {@link ExchangeFilterFunction filter}, or
664                 * add {@code onErrorResume} downstream, for example:
665                 * <pre class="code">
666                 * webClient.get()
667                 *     .uri("https://abc.com/account/123")
668                 *     .retrieve()
669                 *     .bodyToMono(Account.class)
670                 *     .onErrorResume(WebClientResponseException.class,
671                 *          ex -> ex.getRawStatusCode() == 404 ? Mono.empty() : Mono.error(ex));
672                 * </pre>
673                 * @param statusPredicate to match responses with
674                 * @param exceptionFunction to map the response to an error signal
675                 * @return this builder
676                 * @see ClientResponse#createException()
677                 */
678                ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate,
679                                Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction);
680
681                /**
682                 * Variant of {@link #onStatus(Predicate, Function)} that works with
683                 * raw status code values. This is useful for custom status codes.
684                 * @param statusCodePredicate to match responses with
685                 * @param exceptionFunction to map the response to an error signal
686                 * @return this builder
687                 * @since 5.1.9
688                 */
689                ResponseSpec onRawStatus(IntPredicate statusCodePredicate,
690                                Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction);
691
692                /**
693                 * Extract the body to a {@code Mono}. By default, if the response has status code 4xx or
694                 * 5xx, the {@code Mono} will contain a {@link WebClientException}. This can be overridden
695                 * with {@link #onStatus(Predicate, Function)}.
696                 * @param elementClass the expected response body element class
697                 * @param <T> response body type
698                 * @return a mono containing the body, or a {@link WebClientResponseException} if the
699                 * status code is 4xx or 5xx
700                 */
701                <T> Mono<T> bodyToMono(Class<T> elementClass);
702
703                /**
704                 * Extract the body to a {@code Mono}. By default, if the response has status code 4xx or
705                 * 5xx, the {@code Mono} will contain a {@link WebClientException}. This can be overridden
706                 * with {@link #onStatus(Predicate, Function)}.
707                 * @param elementTypeRef a type reference describing the expected response body element type
708                 * @param <T> response body type
709                 * @return a mono containing the body, or a {@link WebClientResponseException} if the
710                 * status code is 4xx or 5xx
711                 */
712                <T> Mono<T> bodyToMono(ParameterizedTypeReference<T> elementTypeRef);
713
714                /**
715                 * Extract the body to a {@code Flux}. By default, if the response has status code 4xx or
716                 * 5xx, the {@code Flux} will contain a {@link WebClientException}. This can be overridden
717         * with {@link #onStatus(Predicate, Function)}.
718                 * @param elementClass the class of elements in the response
719                 * @param <T> the type of elements in the response
720                 * @return a flux containing the body, or a {@link WebClientResponseException} if the
721                 * status code is 4xx or 5xx
722                 */
723                <T> Flux<T> bodyToFlux(Class<T> elementClass);
724
725                /**
726                 * Extract the body to a {@code Flux}. By default, if the response has status code 4xx or
727                 * 5xx, the {@code Flux} will contain a {@link WebClientException}. This can be overridden
728         * with {@link #onStatus(Predicate, Function)}.
729                 * @param elementTypeRef a type reference describing the expected response body element type
730                 * @param <T> the type of elements in the response
731                 * @return a flux containing the body, or a {@link WebClientResponseException} if the
732                 * status code is 4xx or 5xx
733                 */
734                <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> elementTypeRef);
735
736                /**
737                 * Return the response as a delayed {@code ResponseEntity}. By default, if the response has
738                 * status code 4xx or 5xx, the {@code Mono} will contain a {@link WebClientException}. This
739                 * can be overridden with {@link #onStatus(Predicate, Function)}.
740                 * @param bodyClass the expected response body type
741                 * @param <T> response body type
742                 * @return {@code Mono} with the {@code ResponseEntity}
743                 * @since 5.2
744                 */
745                <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyClass);
746
747                /**
748                 * Return the response as a delayed {@code ResponseEntity}. By default, if the response has
749                 * status code 4xx or 5xx, the {@code Mono} will contain a {@link WebClientException}. This
750                 * can be overridden with {@link #onStatus(Predicate, Function)}.
751                 * @param bodyTypeReference a type reference describing the expected response body type
752                 * @param <T> response body type
753                 * @return {@code Mono} with the {@code ResponseEntity}
754                 * @since 5.2
755                 */
756                <T> Mono<ResponseEntity<T>> toEntity(ParameterizedTypeReference<T> bodyTypeReference);
757
758                /**
759                 * Return the response as a delayed list of {@code ResponseEntity}s. By default, if the
760                 * response has status code 4xx or 5xx, the {@code Mono} will contain a
761                 * {@link WebClientException}. This can be overridden with
762                 * {@link #onStatus(Predicate, Function)}.
763                 * @param elementClass the expected response body list element class
764                 * @param <T> the type of elements in the list
765                 * @return {@code Mono} with the list of {@code ResponseEntity}s
766                 * @since 5.2
767                 */
768                <T> Mono<ResponseEntity<List<T>>> toEntityList(Class<T> elementClass);
769
770                /**
771                 * Return the response as a delayed list of {@code ResponseEntity}s. By default, if the
772                 * response has status code 4xx or 5xx, the {@code Mono} will contain a
773                 * {@link WebClientException}. This can be overridden with
774                 * {@link #onStatus(Predicate, Function)}.
775                 * @param elementTypeRef the expected response body list element reference type
776                 * @param <T> the type of elements in the list
777                 * @return {@code Mono} with the list of {@code ResponseEntity}s
778                 * @since 5.2
779                 */
780                <T> Mono<ResponseEntity<List<T>>> toEntityList(ParameterizedTypeReference<T> elementTypeRef);
781
782                /**
783                 * Return the response as a delayed {@code ResponseEntity} containing status and headers,
784                 * but no body.  By default, if the response has status code 4xx or 5xx, the {@code Mono}
785                 * will contain a {@link WebClientException}. This can be overridden with
786                 * {@link #onStatus(Predicate, Function)}.
787                 * Calling this method will {@linkplain ClientResponse#releaseBody() release} the body of
788                 * the response.
789                 * @return {@code Mono} with the bodiless {@code ResponseEntity}
790                 * @since 5.2
791                 */
792                Mono<ResponseEntity<Void>> toBodilessEntity();
793        }
794
795
796        /**
797         * Contract for specifying request headers and URI for a request.
798         * @param <S> a self reference to the spec type
799         */
800        interface RequestHeadersUriSpec<S extends RequestHeadersSpec<S>>
801                        extends UriSpec<S>, RequestHeadersSpec<S> {
802        }
803
804
805        /**
806         * Contract for specifying request headers, body and URI for a request.
807         */
808        interface RequestBodyUriSpec extends RequestBodySpec, RequestHeadersUriSpec<RequestBodySpec> {
809        }
810
811
812}