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.

Programmer DD
Programmer DD
Programmer DD
How to Use Spring 6’s Declarative HTTP Client with @HttpExchange

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 PATCH

Supported parameter annotations:

@PathVariable – path variable
@RequestBody   – request body
@RequestParam   – query parameter
@RequestHeader  – request header
@RequestPart    – multipart part
@CookieValue    – cookie

3. 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();
  }
}
JavaDeclarative HTTP clientSpring Boot 3HttpExchange
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.