Skip to main content

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 to Spring Cloud OpenFeign who are considering migrating to Spring 6.x, making the transition process more challenging.

Quick Start​

implementation("io.github.danielliu1123:httpexchange-spring-boot-starter:<latest>")
@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);
}
}
success

No more boilerplate code! 🎉