REST Client and API Calls

Introduction

Your Spring Boot app often calls other HTTP APIs—payment gateways, SMS providers, or microservices. Spring Boot 3 recommends RestClient (modern) and WebClient (reactive). This chapter configures timeouts, sends GET/POST with JSON, handles errors, and compares choices for typical MVC apps.

Prerequisites

RestClient (Servlet Stack Default Choice)

Boot 3.2+ RestClient builder bean optional; create explicitly:

Code explanation:

  • connectTimeout — TCP connect limit
  • readTimeout — wait for response body

GET Request

DTO:

java
public record PostDto(Long id, String title, String body) {}

Service:

Public test API: https://jsonplaceholder.typicode.com/posts/1

Adjust baseUrl for demos:

java
return builder.baseUrl("https://jsonplaceholder.typicode.com").build();

POST With JSON Body

java
public record CreatePostRequest(String title, String body) {}
 
public PostDto createPost(CreatePostRequest request) {
    return restClient.post()
        .uri("/posts")
        .body(request)
        .retrieve()
        .body(PostDto.class);
}

Error Handling

java
import org.springframework.web.client.RestClientResponseException;
 
public PostDto fetchPostSafe(Long id) {
    try {
        return restClient.get()
            .uri("/posts/{id}", id)
            .retrieve()
            .body(PostDto.class);
    } catch (RestClientResponseException ex) {
        throw new IllegalStateException("Upstream error: " + ex.getStatusCode(), ex);
    }
}

Fluent handler:

java
return restClient.get()
    .uri("/posts/{id}", id)
    .retrieve()
    .onStatus(status -> status.is4xxClientError(), (req, res) -> {
        throw new IllegalArgumentException("Not found: " + id);
    })
    .body(PostDto.class);

Map upstream errors to your global exception handler.

RestTemplate (Legacy)

RestTemplate still works but is in maintenance mode—prefer RestClient for new servlet code:

java
@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

WebClient (Reactive / Fluent)

Add dependency:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Use WebClient when app is reactive end-to-end; blocking RestClient is simpler in classic MVC.

Configuration Externalization

yaml
app:
  upstream:
    base-url: https://api.example.com
    connect-timeout-ms: 3000
    read-timeout-ms: 5000

Bind with @ConfigurationProperties—chapter 14.

Resilience (Awareness)

Production calls add retries, circuit breakers (Resilience4j), and bulkheads when upstream fails often—not covered in depth here.

FAQ

RestClient bean not found?

Add spring-boot-starter-web; inject RestClient.Builder or define @Bean.

SSL certificate errors?

Import trust cert or configure SSL context—never disable verify in prod.

Pass auth header?

java
.defaultHeader("Authorization", "Bearer " + token)

Or per request .header("Authorization", ...).

Connection pool?

RestClient with HttpComponentsClientHttpRequestFactory or JettyClientHttpRequestFactory for pooling under high load.

Timeouts ignored?

Confirm request factory attached to builder.

Log requests?

RestClient interceptors or Spring ClientHttpRequestInterceptor.