- name
- http-interface-clients
- description
- Use when calling external HTTP APIs from Spring Boot 3 / Spring Framework 6 with declarative HttpExchange interfaces. Covers manual proxy registration, RestClient versus WebClient, and timeout and error handling conventions.
Declarative HTTP Interface Clients (Boot 3)
Spring Framework 6 supports @HttpExchange interfaces, but Boot 3 does not provide Boot 4's
@ImportHttpServices group auto-registration. Build the client adapter explicitly.
@HttpExchange("/orders")
interface OrderApiClient {
@GetExchange("/{id}")
OrderDto get(@PathVariable UUID id);
}
@Configuration
class ClientConfig {
@Bean
OrderApiClient orderApiClient(RestClient.Builder builder,
@Value("${clients.orders.base-url}") String baseUrl) {
RestClient client = builder.baseUrl(baseUrl).build();
HttpServiceProxyFactory factory =
HttpServiceProxyFactory.builderFor(RestClientAdapter.create(client)).build();
return factory.createClient(OrderApiClient.class);
}
}
Use WebClientAdapter for reactive interfaces returning Mono or Flux. Configure base URLs,
timeouts, authentication, and error translation in the client adapter layer rather than in
controllers or domain services. Prefer one factory/configurer per external service.
Transport failure contract
Define an adapter policy before adding retry annotations. The companion
CatalogHttpClient implements the
CatalogRetryService.CatalogTransport port from the resilience-retry skill and uses
explicit JDK connect/read timeouts. It is a small imperative adapter example, not a reason
to replace an existing HTTP interface or Boot-managed client.
For POST/payment calls, preserve the same idempotency key and request bytes across retries; a timeout does not prove the server did nothing. Never forward inbound Authorization to an arbitrary destination: configure credentials per trusted service. Do not allow an end user to choose the base URL. Avoid logging tokens or raw upstream error bodies.