Declarative HTTP interface with Spring Framework 6

Declarative HTTP interface with Spring Framework 6

In this article, we'll learn about the declarative HTTP interface integration with spring framework 6. In the current spring framework-based application, we need to write an implementation of the HTTP client with lots of boilerplate code. As part of the latest version of spring 6, we just need to declare the HTTP client as the interface and the spring framework generates implementation for us.

As part of this demo, we'll create two spring boot applications frontend-rest and backend-rest. The backend-rest application will expose rest endpoints and the frontend-rest application will use a declarative way to connect the REST endpoint exposed by the backend application. We will use the spring boot of version 3.0.0-SNAPSHOT as the release version is not released yet. The JDK version supported by spring framework 6 is 17+ so we will use JDK 17 as part of this demo.

I have added a core code snippet as part of this article. For full code reference, refer frontend-rest and backend-rest

Prerequisites

  • JDK 17+
  • Maven
  • Basic knowledge of Java, Spring boot

Backend-rest application

  • This is a spring boot application that exposes the REST endpoints that any other application can consume. These endpoints give details about the person by name and list of the person.
  • As part of this demo, we'll create static data as shown below and add two endpoints.
@RestController
public class BackendController {
    private Map<String, Person> personMap = new HashMap<>();
    {
        personMap.put("Yogesh", new Person("Yogesh", 31, "London"));
        personMap.put("Raj", new Person("Raj", 35, "Mumbai"));
        personMap.put("Tom", new Person("Tom", 34, "Paris"));
    }
    @RequestMapping(value = "/person/{name}", method = RequestMethod.GET)
    public Person personByName(@PathVariable String name) {
        return personMap.get(name);
    }
    @RequestMapping(value = "/person", method = RequestMethod.GET)
    public List<Person> personList() {
        return new ArrayList<>(personMap.values());
    }
}

Frontend-rest application

  • This is the spring boot application that consumes REST endpoints from backend-rest services. Here we'll use a new feature of the spring framework HTTP interface so we do not need to write boilerplate code.
Create HTTP interface
  • As shown below, create an HTTP interface, spring boot application will take care of the implementation part.
public interface PersonService {
    @GetExchange("/person/{name}")
    Person personByName(@PathVariable String name);
    @GetExchange("/person")
    List<Person> personList();
}
Configure the HTTP interface
  • As shown below, configure HTTP services with base URL.
    @Bean
    PersonService personService(){
        WebClient client = WebClient.builder()
                .baseUrl("http://localhost:8080/")
                .build();

        HttpServiceProxyFactory proxyFactory =
                HttpServiceProxyFactory.builder(new WebClientAdapter(client)).build();

        return proxyFactory.createClient(PersonService.class);
    }
Consume REST API details
  • As shown below, call REST API to get person details by name and list of the person. Below code will be executed on application startup.
@Bean
    public CommandLineRunner CommandLineRunnerBean() {
        return (args) -> {
            System.out.println("by name " + personService().personByName("Yogesh"));
            System.out.println("list " + personService().personList());
        };
    }
  • As shown below, the output of both calls will be in JSON format.
2022-06-02T13:52:01.756+01:00  INFO 28868 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2022-06-02T13:52:01.772+01:00  INFO 28868 --- [           main] c.e.f.FrontendRestApplication            : Started FrontendRestApplication in 5.304 seconds (process running for 6.327)
by name Person{name='Yogesh', age=31, city='London'}
list [Person{name='Yogesh', age=31, city='London'}, Person{name='Tom', age=34, city='Paris'}, Person{name='Raj', age=35, city='Mumbai'}]