Declarative REST Clients with Spring Framework 6

Benedikt Jerat
Digital Frontiers — Das Blog
3 min readFeb 3, 2023
Photo by Johannes Plenio on Unsplash

My first contact with a declarative REST client was with Feign, back then part of the Spring Cloud Netflix stack, long ago relabelled as Spring Cloud OpenFeign. Prior to that, it was always tedious to write those HTTP calls via the RestTemplate, similar code every time. With Feign you just defined an interface with the method contracts mirroring the services’ endpoint and some proxy magic in the background generated a ready to use HTTP client. Amazing!

Now, with the release of Spring Framework 6, such a declarative REST client became native part of the core web framework: Say hello to the HTTP Interface!

All necessary components are in the spring-web module, that happens to be a transitive dependency for the spring-boot-starter-web or the spring-boot-starter-webflux modules. However, in practice the WebFlux dependency is always required at the moment due to the HttpServiceProxyFactory for generating the clients. If you have a workaround for this, just let me know in the comments :)

Internally, the new declarative HTTP clients make use of the WebClient, which is the recommended client for HTTP requests since Spring 5. But as you will see, there won’t be that much touch points with it overall.

An example HTTP client

First, let’s define a client for our small application:

As you already see, there’s no implementation, only an interface declaration with annotated fields and methods. For the fields, annotations like @RequestParam, @PathVariable, or @RequestBody should be well-known. These are the same we use in a Spring REST controller. For the methods, we have @...Exchange methods for the most common HTTP verbs (get, put, post, delete, and patch). We may also use the general annotation @HttpExchange on method-level, but this does not bring any added value. On type-level however, we can use the @HttpExchange annotation to define common attributes, like the url or media types for our client.

The CharacterClient can be autowired like any other bean and used similarly to a Feign client:

This already looks very simple and, above all, comfortable to use. As already mentioned, the implementation is using a WebClient. However, fortunately all the internals of the WebClient are abstracted away. If we compare this with calls against it directly, we immediately observe how much boilerplate code we can avoid:

Pretty neat! Why would you want to implement something yourself when you can have it generated just as well?

The HttpServiceProxyFactory for client generation

If you followed the code up until this point, you will already have discovered that our declarative HTTP client CharacterClient cannot be autowired without further work. There’s one thing missing: How do we actually bind the WebClient to our declarative HTTP client?

The client needs to be generated by the HttpServiceProxyFactory and manually bound to a WebClient instance that you define. In our example, the configuration class looks like this:

Currently, unlike OpenFeign, the client is not yet supplied via auto-configuration in a Spring Boot setup (kindly track Support declarative HTTP clients #31337 for that matter). Therefore, we build a WebClient ourselves and create a declarative HTTP client from it by using the createClient method from HttpServiceProxyFactory. This is some kind of boilerplate code, but I am quite confident that the Spring Boot guys will come up with a nice solution to simplify this further. Up until this point, you will need such a bean definition for each declarative HTTP client in your application.

And that only leaves one more thing to say: Just try out the new declarative HTTP client yourself! In comparison to using the WebClient directly, a lot of boilerplate code is abstracted away. Another advantage is that we do not need any additional dependency for the HTTP client, as it comes along transitively as part of spring-web in Spring Framework 6 or Spring Boot 3.

Thanks for reading! Feel free to comment or message me, when you have questions or suggestions. You might be interested in the other posts published in the Digital Frontiers blog, announced on our Twitter account.

--

--