Introduction
Spring 6 brings native support for declarative HTTP clients with the
@HttpExchange
annotation. This new feature allows you to replace the dependency on
Spring Cloud OpenFeign effectively.
Here is an example:
@HttpExchange("https://my-json-server.typicode.com")
interface PostApi {
@GetExchange("/typicode/demo/posts/{id}")
Post getPost(@PathVariable("id") int id);
}
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Bean
PostApi postApi(RestClient.Builder builder) {
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builderFor(RestClientAdapter.create(builder.build()))
.build();
return factory.createClient(PostApi.class);
}
// Imagine there are 100 HttpExchange clients 😇
@Bean
ApplicationRunner runner(PostApi api) {
return args -> api.getPost(1);
}
}
Identified Issues​
-
Lack of Autoconfiguration
Currently, autoconfiguration is not available for clients, requiring manual instantiation through client beans. This process can become particularly cumbersome when managing numerous clients.
For users familiar with
Spring Cloud OpenFeign
, the@EnableFeignClients
annotation is highly beneficial, significantly reducing repetitive code. -
Absence of Support for Spring Web Annotations
Although native support for declarative HTTP clients is a valuable addition, it introduces a new set of annotations like
@GetExchange
,@PostExchange
, etc. Unfortunately,HttpServiceProxyFactory
does not support Spring web annotations, such as@GetMapping
and@PostMapping
. This lack of support can be a significant obstacle for users accustomed toSpring Cloud OpenFeign
who are considering migrating to Spring 6.x, making the transition process more challenging.
Quick Start​
- Gradle
- Maven
implementation("io.github.danielliu1123:httpexchange-spring-boot-starter:<latest>")
<dependency>
<groupId>io.github.danielliu1123</groupId>
<artifactId>httpexchange-spring-boot-starter</artifactId>
<version>latest</version>
</dependency>
@HttpExchange("https://my-json-server.typicode.com")
interface PostApi {
@GetExchange("/typicode/demo/posts/{id}")
Post getPost(@PathVariable("id") int id);
}
@SpringBootApplication
@EnableExchangeClients
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Bean
ApplicationRunner runner(PostApi api) {
return args -> api.getPost(1);
}
}
No more boilerplate code! 🎉