Client support for API versioning
Closes gh-34567
This commit is contained in:
@@ -52,6 +52,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.ApiVersionInserter;
|
||||
import org.springframework.web.reactive.function.BodyExtractor;
|
||||
import org.springframework.web.reactive.function.BodyInserter;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
@@ -93,6 +94,8 @@ final class DefaultWebClient implements WebClient {
|
||||
|
||||
private final @Nullable MultiValueMap<String, String> defaultCookies;
|
||||
|
||||
private final @Nullable ApiVersionInserter apiVersionInserter;
|
||||
|
||||
private final @Nullable Consumer<RequestHeadersSpec<?>> defaultRequest;
|
||||
|
||||
private final List<DefaultResponseSpec.StatusHandler> defaultStatusHandlers;
|
||||
@@ -106,7 +109,9 @@ final class DefaultWebClient implements WebClient {
|
||||
|
||||
DefaultWebClient(ExchangeFunction exchangeFunction, @Nullable ExchangeFilterFunction filterFunctions,
|
||||
UriBuilderFactory uriBuilderFactory, @Nullable HttpHeaders defaultHeaders,
|
||||
@Nullable MultiValueMap<String, String> defaultCookies, @Nullable Consumer<RequestHeadersSpec<?>> defaultRequest,
|
||||
@Nullable MultiValueMap<String, String> defaultCookies,
|
||||
@Nullable ApiVersionInserter apiVersionInserter,
|
||||
@Nullable Consumer<RequestHeadersSpec<?>> defaultRequest,
|
||||
@Nullable Map<Predicate<HttpStatusCode>, Function<ClientResponse, Mono<? extends Throwable>>> statusHandlerMap,
|
||||
ObservationRegistry observationRegistry, @Nullable ClientRequestObservationConvention observationConvention,
|
||||
DefaultWebClientBuilder builder) {
|
||||
@@ -116,6 +121,7 @@ final class DefaultWebClient implements WebClient {
|
||||
this.uriBuilderFactory = uriBuilderFactory;
|
||||
this.defaultHeaders = defaultHeaders;
|
||||
this.defaultCookies = defaultCookies;
|
||||
this.apiVersionInserter = apiVersionInserter;
|
||||
this.defaultRequest = defaultRequest;
|
||||
this.defaultStatusHandlers = initStatusHandlers(statusHandlerMap);
|
||||
this.observationRegistry = observationRegistry;
|
||||
@@ -205,6 +211,8 @@ final class DefaultWebClient implements WebClient {
|
||||
|
||||
private @Nullable MultiValueMap<String, String> cookies;
|
||||
|
||||
private @Nullable Object apiVersion;
|
||||
|
||||
private @Nullable BodyInserter<?, ? super ClientHttpRequest> inserter;
|
||||
|
||||
private final Map<String, Object> attributes = new LinkedHashMap<>(4);
|
||||
@@ -323,6 +331,12 @@ final class DefaultWebClient implements WebClient {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultRequestBodyUriSpec apiVersion(Object version) {
|
||||
this.apiVersion = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec attribute(String name, Object value) {
|
||||
this.attributes.put(name, value);
|
||||
@@ -474,7 +488,12 @@ final class DefaultWebClient implements WebClient {
|
||||
}
|
||||
|
||||
private URI initUri() {
|
||||
return (this.uri != null ? this.uri : uriBuilderFactory.expand(""));
|
||||
URI uriToUse = (this.uri != null ? this.uri : uriBuilderFactory.expand(""));
|
||||
if (this.apiVersion != null) {
|
||||
Assert.state(apiVersionInserter != null, "No ApiVersionInserter configured");
|
||||
uriToUse = apiVersionInserter.insertVersion(this.apiVersion, uriToUse);
|
||||
}
|
||||
return uriToUse;
|
||||
}
|
||||
|
||||
private void initHeaders(HttpHeaders out) {
|
||||
@@ -484,6 +503,10 @@ final class DefaultWebClient implements WebClient {
|
||||
if (this.headers != null && !this.headers.isEmpty()) {
|
||||
out.putAll(this.headers);
|
||||
}
|
||||
if (this.apiVersion != null) {
|
||||
Assert.state(apiVersionInserter != null, "No ApiVersionInserter configured");
|
||||
apiVersionInserter.insertVersion(this.apiVersion, out);
|
||||
}
|
||||
}
|
||||
|
||||
private void initCookies(MultiValueMap<String, String> out) {
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.ApiVersionInserter;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
import org.springframework.web.util.UriBuilderFactory;
|
||||
|
||||
@@ -80,6 +81,8 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
|
||||
private @Nullable MultiValueMap<String, String> defaultCookies;
|
||||
|
||||
private @Nullable ApiVersionInserter apiVersionInserter;
|
||||
|
||||
private @Nullable Consumer<WebClient.RequestHeadersSpec<?>> defaultRequest;
|
||||
|
||||
private @Nullable Map<Predicate<HttpStatusCode>, Function<ClientResponse, Mono<? extends Throwable>>> statusHandlers;
|
||||
@@ -118,8 +121,9 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
this.defaultHeaders = null;
|
||||
}
|
||||
|
||||
this.defaultCookies = (other.defaultCookies != null ?
|
||||
new LinkedMultiValueMap<>(other.defaultCookies) : null);
|
||||
this.defaultCookies = (other.defaultCookies != null ? new LinkedMultiValueMap<>(other.defaultCookies) : null);
|
||||
this.apiVersionInserter = other.apiVersionInserter;
|
||||
|
||||
this.defaultRequest = other.defaultRequest;
|
||||
this.statusHandlers = (other.statusHandlers != null ? new LinkedHashMap<>(other.statusHandlers) : null);
|
||||
this.filters = (other.filters != null ? new ArrayList<>(other.filters) : null);
|
||||
@@ -190,6 +194,13 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
return this.defaultCookies;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WebClient.Builder apiVersionInserter(ApiVersionInserter apiVersionInserter) {
|
||||
this.apiVersionInserter = apiVersionInserter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient.Builder defaultRequest(Consumer<WebClient.RequestHeadersSpec<?>> defaultRequest) {
|
||||
this.defaultRequest = this.defaultRequest != null ?
|
||||
@@ -297,6 +308,7 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
return new DefaultWebClient(
|
||||
exchange, filterFunctions,
|
||||
initUriBuilderFactory(), defaultHeaders, defaultCookies,
|
||||
this.apiVersionInserter,
|
||||
this.defaultRequest,
|
||||
this.statusHandlers,
|
||||
this.observationRegistry, this.observationConvention,
|
||||
|
||||
@@ -45,6 +45,8 @@ import org.springframework.http.client.reactive.ClientHttpRequest;
|
||||
import org.springframework.http.client.reactive.ClientHttpResponse;
|
||||
import org.springframework.http.codec.ClientCodecConfigurer;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.ApiVersionFormatter;
|
||||
import org.springframework.web.client.ApiVersionInserter;
|
||||
import org.springframework.web.reactive.function.BodyExtractor;
|
||||
import org.springframework.web.reactive.function.BodyInserter;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
@@ -250,6 +252,15 @@ public interface WebClient {
|
||||
*/
|
||||
Builder defaultCookies(Consumer<MultiValueMap<String, String>> cookiesConsumer);
|
||||
|
||||
/**
|
||||
* Configure an {@link ApiVersionInserter} to abstract how an API version
|
||||
* specified via {@link RequestHeadersSpec#apiVersion(Object)}
|
||||
* is inserted into the request.
|
||||
* @param apiVersionInserter the inserter to use
|
||||
* @since 7.0
|
||||
*/
|
||||
Builder apiVersionInserter(ApiVersionInserter apiVersionInserter);
|
||||
|
||||
/**
|
||||
* Provide a consumer to customize every request being built.
|
||||
* @param defaultRequest the consumer to use for modifying requests
|
||||
@@ -475,6 +486,17 @@ public interface WebClient {
|
||||
*/
|
||||
S headers(Consumer<HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Set an API version for the request. The version is inserted into the
|
||||
* request by the {@link Builder#apiVersionInserter(ApiVersionInserter)
|
||||
* configured} {@code ApiVersionInserter}.
|
||||
* @param version the API version of the request; this can be a String or
|
||||
* some Object that can be formatted the inserter, e.g. through an
|
||||
* {@link ApiVersionFormatter}.
|
||||
* @since 7.0
|
||||
*/
|
||||
S apiVersion(Object version);
|
||||
|
||||
/**
|
||||
* Set the attribute with the given name to the given value.
|
||||
* @param name the name of the attribute to add
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -127,6 +127,11 @@ public final class WebClientAdapter extends AbstractReactorHttpExchangeAdapter {
|
||||
|
||||
bodySpec.headers(headers -> headers.putAll(values.getHeaders()));
|
||||
bodySpec.cookies(cookies -> cookies.putAll(values.getCookies()));
|
||||
|
||||
if (values.getApiVersion() != null) {
|
||||
bodySpec.apiVersion(values.getApiVersion());
|
||||
}
|
||||
|
||||
bodySpec.attributes(attributes -> attributes.putAll(values.getAttributes()));
|
||||
|
||||
if (values.getBodyValue() != null) {
|
||||
|
||||
Reference in New Issue
Block a user