DEV Community

Jan Mewes
Jan Mewes

Posted on

Getting started with Spring RestClient

With Spring Framework v6.1 and Spring Boot v3.2 the RestClient class was introduced as alternative to RestTemplate. It can be used for creating synchronous outbound HTTP requests with a fluent API. This blog post provides examples of how the RestClient can be used in a Spring Boot project.

Getting started

The first step in creating an HTTP request is to create an instance of the RestClient class. Using the RestClient.Builder, a common base URL can be used for all requests.

The RestClient then provides e.g. the methods post(), put(), get() and delete() for starting to build a request. The request can then be provided with a specific resource path, request headers, etc. Finally, by calling retrieve().toEntity(String.class) the request is executed and the response payload is mapped to a String.

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;

@Component
class ExampleRestClient {

    private final RestClient restClient;

    ExampleRestClient() {
        restClient = RestClient.builder()
            .baseUrl("https://example.com")
            .build();
    }

    ResponseEntity<String> getExample() {
        return restClient.get()
            .uri("/example")
            .header("X-Foo", "bar")
            .retrieve()
            .toEntity(String.class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Query parameters

For URLs with query parameters (aka. URL Search Params), the UriBuilder can be used.

@Component
class ExampleRestClient {

    // ...

    ResponseEntity<String> getExample() {
        return restClient.get()
            .uri(uriBuilder -> uriBuilder.path("/example").queryParam("foo", "bar").build())
            .retrieve()
            .toEntity(String.class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Logbook

Sometimes it may be useful to log the details of the outgoing requests and incoming responses. For this purpose, the Logbook library may be used in combination with the Apache HTTP client.

To make it work, an Apache HTTP client needs to be created, with a Logbook instance registered as interceptor. Then the Apache HTTP client needs to be provided to the RestClient.Builder as the client request factory to be used.

import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.zalando.logbook.Logbook;
import org.zalando.logbook.core.WithoutBodyStrategy;
import org.zalando.logbook.httpclient5.LogbookHttpExecHandler;

@Component
class ExampleRestClient {

    private final RestClient restClient;

    ExampleRestClient() {
        final Logbook logbook = Logbook.builder()
            .strategy(new WithoutBodyStrategy())
            .build();
        final CloseableHttpClient client = HttpClientBuilder.create()
            .addExecInterceptorFirst("Logbook", new LogbookHttpExecHandler(logbook))
            .build();

        restClient = RestClient.builder()
            .requestFactory(new HttpComponentsClientHttpRequestFactory(client))
            .baseUrl("https://example.com")
            .build();
    }

    ResponseEntity<String> getExample() {
        return restClient.get()
            .uri("/")
            .retrieve()
            .toEntity(String.class);
    }
}
Enter fullscreen mode Exit fullscreen mode

The following dependencies are required for this:

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version>
</dependency>

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-core</artifactId>
    <version>3.9.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-httpclient5</artifactId>
    <version>3.9.0</version>
    <scope>test</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode

After enabling the TRACE level for the org.zalando.logbook Logger in the application.properties, the outbound HTTP requests from the ExampleRestClient will be logged.

logging.level.org.zalando.logbook: TRACE
Enter fullscreen mode Exit fullscreen mode

Here is an example of the log messages created for the example request:

2024-09-15T20:34:24.013+02:00 TRACE 1892 --- [hello-spring] [nio-8080-exec-1] org.zalando.logbook.Logbook              : Outgoing Request: b7259e7febeb49f5
Remote: localhost
GET https://example.com/ HTTP/1.1
2024-09-15T20:34:24.570+02:00 TRACE 1892 --- [hello-spring] [nio-8080-exec-1] org.zalando.logbook.Logbook              : Incoming Response: b7259e7febeb49f5
Duration: 564 ms
HTTP/1.1 200 OK
Accept-Ranges: bytes
Age: 476506
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Sun, 15 Sep 2024 18:34:24 GMT
Etag: "3147526947+gzip"
Expires: Sun, 22 Sep 2024 18:34:24 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECAcc (mid/8751)
Vary: Accept-Encoding
X-Cache: HIT
Enter fullscreen mode Exit fullscreen mode

References

Top comments (0)