Skip to content

Commit

Permalink
Resolve URI to baseUrl in RestClient
Browse files Browse the repository at this point in the history
Closes gh-32679
  • Loading branch information
poutsma committed Jul 1, 2024
1 parent 98e89d8 commit 5864f57
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,13 @@ public RequestBodySpec uri(Function<UriBuilder, URI> uriFunction) {

@Override
public RequestBodySpec uri(URI uri) {
this.uri = uri;
if (uri.isAbsolute()) {
this.uri = uri;
}
else {
URI baseUri = DefaultRestClient.this.uriBuilderFactory.expand("");
this.uri = baseUri.resolve(uri);
}
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.web.client;

import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -245,6 +246,12 @@ public RestClient.Builder baseUrl(String baseUrl) {
return this;
}

@Override
public RestClient.Builder baseUrl(URI baseUrl) {
this.baseUrl = baseUrl.toString();
return this;
}

@Override
public RestClient.Builder defaultUriVariables(Map<String, ?> defaultUriVariables) {
this.defaultUriVariables = defaultUriVariables;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,17 @@ static RestClient create(String baseUrl) {
return new DefaultRestClientBuilder().baseUrl(baseUrl).build();
}

/**
* Variant of {@link #create()} that accepts a default base {@code URI}. For more
* details see {@link Builder#baseUrl(URI) Builder.baseUrl(URI)}.
* @param baseUrl the base URI for all requests
* @since 6.2
* @see #builder()
*/
static RestClient create(URI baseUrl) {
return new DefaultRestClientBuilder().baseUrl(baseUrl).build();
}

/**
* Create a new {@code RestClient} based on the configuration of the given
* {@code RestTemplate}.
Expand Down Expand Up @@ -230,6 +241,26 @@ interface Builder {
*/
Builder baseUrl(String baseUrl);

/**
* Configure a base {@code URI} for requests. Effectively a shortcut for:
* <pre class="code">
* URI baseUrl = URI.create("https://abc.go.com/v1");
* DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl.toString());
* RestClient client = RestClient.builder().uriBuilderFactory(factory).build();
* </pre>
* <p>The {@code DefaultUriBuilderFactory} is used to prepare the URL
* for every request with the given base URL, unless the URL request
* for a given URL is absolute in which case the base URL is ignored.
* <p><strong>Note:</strong> this method is mutually exclusive with
* {@link #uriBuilderFactory(UriBuilderFactory)}. If both are used, the
* {@code baseUrl} value provided here will be ignored.
* @return this builder
* @since 6.2
* @see DefaultUriBuilderFactory#DefaultUriBuilderFactory(String)
* @see #uriBuilderFactory(UriBuilderFactory)
*/
Builder baseUrl(URI baseUrl);

/**
* Configure default URL variable values to use when expanding URI
* templates with a {@link Map}. Effectively a shortcut for:
Expand Down Expand Up @@ -414,7 +445,11 @@ Builder defaultStatusHandler(Predicate<HttpStatusCode> statusPredicate,
interface UriSpec<S extends RequestHeadersSpec<?>> {

/**
* Specify the URI using an absolute, fully constructed {@link URI}.
* Specify the URI using a fully constructed {@link URI}.
* <p>If the given URI is absolute, it is used as given. If it is
* a relative URI, the {@link UriBuilderFactory} configured for
* the client (e.g. with a base URI) will be used to
* {@linkplain URI#resolve(URI) resolve} the given URI against.
*/
S uri(URI uri);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.web.client;

import java.lang.reflect.Field;
import java.net.URI;
import java.util.List;

import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -90,6 +91,18 @@ void defaultUriBuilderFactory() {
assertThat(fieldValue("uriBuilderFactory", defaultBuilder)).isNull();
}

@Test
void defaultUri() {
URI baseUrl = URI.create("https://example.org");
RestClient.Builder builder = RestClient.builder();
builder.baseUrl(baseUrl);

assertThat(builder).isInstanceOf(DefaultRestClientBuilder.class);
DefaultRestClientBuilder defaultBuilder = (DefaultRestClientBuilder) builder;

assertThat(fieldValue("baseUrl", defaultBuilder)).isEqualTo(baseUrl.toString());
}

@Nullable
private static Object fieldValue(String name, DefaultRestClientBuilder instance) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -923,6 +925,28 @@ void defaultRequestOverride(ClientHttpRequestFactory requestFactory) {
expectRequest(request -> assertThat(request.getHeader("Accept")).isEqualTo(MediaType.TEXT_PLAIN_VALUE));
}

@ParameterizedRestClientTest
void relativeUri(ClientHttpRequestFactory requestFactory) throws URISyntaxException {
startServer(requestFactory);

prepareResponse(response -> response.setHeader("Content-Type", "text/plain")
.setBody("Hello Spring!"));

URI uri = new URI(null, null, "/foo bar", null);

String result = this.restClient
.get()
.uri(uri)
.accept(MediaType.TEXT_PLAIN)
.retrieve()
.body(String.class);

assertThat(result).isEqualTo("Hello Spring!");

expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/foo%20bar"));
}


private void prepareResponse(Consumer<MockResponse> consumer) {
MockResponse response = new MockResponse();
Expand Down

0 comments on commit 5864f57

Please sign in to comment.