RestClient

Calling Another API

Your backend often calls other services: a payment gateway, an SMS provider, a courier API. Since Spring Boot 3.2 the recommended blocking client is RestClient: a fluent API on top of the same message converters you already use. (RestTemplate still works but is in maintenance mode.)

@Configuration
class HttpClientsConfig {
    @Bean
    RestClient courierClient(RestClient.Builder builder) {      // Builder is auto-configured by Boot
        return builder
                .baseUrl("https://api.fastcourier.example")
                .defaultHeader("X-Api-Key", "demo-key")
                .build();
    }
}

public record TrackingInfo(String awb, String status, String location) {}

@Service
class CourierService {
    private final RestClient client;
    CourierService(RestClient courierClient) { this.client = courierClient; }

    TrackingInfo track(String awb) {
        return client.get()
                .uri("/v1/shipments/{awb}", awb)
                .retrieve()
                .body(TrackingInfo.class);       // JSON -> record via Jackson
    }
}

POST with a Body and Reading the Status

public record CreateShipment(String orderId, String pincode, int weightGrams) {}
public record ShipmentCreated(String awb, String eta) {}

ResponseEntity<ShipmentCreated> response = client.post()
        .uri("/v1/shipments")
        .contentType(MediaType.APPLICATION_JSON)
        .body(new CreateShipment("SE-1001", "560001", 350))
        .retrieve()
        .toEntity(ShipmentCreated.class);

System.out.println(response.getStatusCode() + " " + response.getBody());

Console output:

201 CREATED ShipmentCreated[awb=FC77812093IN, eta=2026-10-15]

Tip: For lists use .body(new ParameterizedTypeReference<List<TrackingInfo>>() {}).

HTTP Interfaces

Spring 6 can generate a client from an annotated interface, much like Feign:

public interface CourierApi {
    @GetExchange("/v1/shipments/{awb}")
    TrackingInfo track(@PathVariable String awb);

    @PostExchange("/v1/shipments")
    ShipmentCreated create(@RequestBody CreateShipment request);
}

@Bean
CourierApi courierApi(RestClient courierClient) {
    HttpServiceProxyFactory factory = HttpServiceProxyFactory
            .builderFor(RestClientAdapter.create(courierClient)).build();
    return factory.createClient(CourierApi.class);
}