How to Use Spring 6’s Declarative HTTP Client with @HttpExchange
This tutorial explains Spring 6 and Spring Boot 3's built‑in support for declarative HTTP clients, showing how to define annotated Java interfaces, configure Maven dependencies, inject WebClient, and write unit tests with code examples.
From Spring 6 and Spring Boot 3, the Spring framework supports turning remote HTTP services into Java HTTP interfaces annotated with specific annotations.
What is a declarative client
Declarative HTTP clients aim to make writing Java HTTP clients easier. By processing annotations, the framework automatically generates requests (officially called declarative or templated). This lets you invoke an HTTP request as if calling a local method, reducing coding effort and improving readability.
Example: to call /tenants, define an interface:
public interface TenantClient {
@GetExchange("/tenants")
Flux<User> getAll();
}Spring provides a runtime implementation, allowing you to call the method like a regular Java method.
@Autowired
TenantClient tenantClient;
tenantClient.getAll().subscribe();Testing usage
1. Maven dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- For WebClient support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>Note: The current implementation only supports non‑blocking WebClient, so WebFlux must be added.
2. Create Http interface type
Add @HttpExchange on the interface to declare it as an HTTP endpoint.
@HttpExchange
public interface DemoApi {
@GetExchange("/admin/tenant/list")
String list();
}Supported method annotations:
@GetExchange – HTTP GET
@PostExchange – HTTP POST
@PutExchange – HTTP PUT
@DeleteExchange – HTTP DELETE
@PatchExchange – HTTP PATCHSupported parameter annotations:
@PathVariable – path variable
@RequestBody – request body
@RequestParam – query parameter
@RequestHeader – request header
@RequestPart – multipart part
@CookieValue – cookie3. Inject declarative client
Inject a WebClient with the target base URL into HttpServiceProxyFactory to bind the client and interface.
@Bean
DemoApi demoApi() {
WebClient client = WebClient.builder().baseUrl("http://pigx.pigx.vip/").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
return factory.createClient(DemoApi.class);
}4. Unit test calling the HTTP interface
@SpringBootTest
class DemoApplicationTests {
@Autowired
private DemoApi demoApi;
@Test
void testDemoApi() {
demoApi.list();
}
}Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
