How to Use Spring 6/Boot 3 HTTP Interface for Declarative REST Clients
This guide explains how Spring 6/Boot 3’s built‑in HTTP interface lets you define declarative REST clients with annotated Java interfaces, covering setup, required Maven dependencies, interface creation, supported annotations, bean configuration, and unit testing with code examples.
http interface
Since Spring 6 and Spring Boot 3, the Spring framework can proxy remote HTTP services as Java interfaces annotated with specific annotations. Existing libraries such as OpenFeign and Retrofit remain usable, but the http interface adds built‑in support.
What is a declarative client
A declarative HTTP client aims to simplify writing Java HTTP clients. It automatically generates requests by processing annotations (officially called declarative or templated). With a declarative client, a HTTP request can be invoked like a local method, reducing coding effort and improving readability.
Example: to call the
/tenantsendpoint, define the following interface:
<code>public interface TenantClient {
@GetExchange("/tenants")
Flux<User> getAll();
}</code>Spring provides a runtime implementation of the interface, allowing the request to be called as a Java method.
<code>@Autowired
TenantClient tenantClient;
tenantClient.getAll().subscribe();
</code>Testing usage
1. Maven dependencies
<code><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>
</code>Currently only the non‑blocking WebClient implementation of http interface is provided, so the webflux starter must be added.
2. Create an Http interface type
Add
@HttpExchangeon the interface to declare it as an http interface endpoint.
<code>@HttpExchange
public interface DemoApi {
@GetExchange("/admin/tenant/list")
String list();
}
</code>Supported method‑level annotations:
<code>@GetExchange: for HTTP GET requests.
@PostExchange: for HTTP POST requests.
@PutExchange: for HTTP PUT requests.
@DeleteExchange: for HTTP DELETE requests.
@PatchExchange: for HTTP PATCH requests.
</code>Supported parameter annotations:
<code>@PathVariable: placeholder parameter.
@RequestBody: request body.
@RequestParam: request parameter.
@RequestHeader: request header.
@RequestPart: form request.
@CookieValue: request cookie.
</code>3. Inject the declarative client
Inject a WebClient with the target baseUrl into HttpServiceProxyFactory, then create the client.
<code>@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);
}
</code>4. Unit test the http interface
<code>@SpringBootTest
class DemoApplicationTests {
@Autowired
private DemoApi demoApi;
@Test
void testDemoApi() {
demoApi.list();
}
}
</code>Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
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.