DEV Community

Dev Cookies
Dev Cookies

Posted on

๐Ÿš€ Complete Guide to Consuming APIs in Spring Boot

With RestTemplate, WebClient, and FeignClient (Headers, Clean Code, CRUD)


In modern microservice or distributed system architecture, it's crucial to know how to consume REST APIs effectively. In this guide, weโ€™ll explore three powerful ways to consume APIs in Spring Boot:

  • ๐Ÿ”— RestTemplate โ€“ classic and synchronous.
  • โšก WebClient โ€“ reactive and non-blocking.
  • ๐Ÿค FeignClient โ€“ declarative and elegant.

Weโ€™ll build a common User model and implement full CRUD operations with all HTTP headers (e.g., Authorization, Content-Type, Accept).


๐Ÿงฉ Common User Model

public class User {
    private Long id;
    private String name;
    private String email;

    // Constructors, Getters, Setters
}
Enter fullscreen mode Exit fullscreen mode

1๏ธโƒฃ RestTemplate โ€“ Synchronous HTTP Client

โœ… Use when you're building traditional apps with blocking I/O.

@Service
public class UserRestTemplateService {
    private final RestTemplate restTemplate = new RestTemplate();
    private final String BASE_URL = "http://localhost:8081/users";

    private HttpHeaders getDefaultHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        headers.set("Authorization", "Bearer your_token_here");
        return headers;
    }

    public User getUser(Long id) {
        HttpEntity<Void> entity = new HttpEntity<>(getDefaultHeaders());
        ResponseEntity<User> response = restTemplate.exchange(BASE_URL + "/" + id, HttpMethod.GET, entity, User.class);
        return response.getBody();
    }

    public User[] getAllUsers() {
        HttpEntity<Void> entity = new HttpEntity<>(getDefaultHeaders());
        ResponseEntity<User[]> response = restTemplate.exchange(BASE_URL, HttpMethod.GET, entity, User[].class);
        return response.getBody();
    }

    public User createUser(User user) {
        HttpEntity<User> entity = new HttpEntity<>(user, getDefaultHeaders());
        ResponseEntity<User> response = restTemplate.exchange(BASE_URL, HttpMethod.POST, entity, User.class);
        return response.getBody();
    }

    public void updateUser(Long id, User user) {
        HttpEntity<User> entity = new HttpEntity<>(user, getDefaultHeaders());
        restTemplate.exchange(BASE_URL + "/" + id, HttpMethod.PUT, entity, Void.class);
    }

    public void deleteUser(Long id) {
        HttpEntity<Void> entity = new HttpEntity<>(getDefaultHeaders());
        restTemplate.exchange(BASE_URL + "/" + id, HttpMethod.DELETE, entity, Void.class);
    }
}
Enter fullscreen mode Exit fullscreen mode

2๏ธโƒฃ WebClient โ€“ Reactive and Non-Blocking

โœ… Use when building reactive microservices or high-concurrency apps.

@Service
public class UserWebClientService {
    private final WebClient webClient = WebClient.builder()
            .baseUrl("http://localhost:8081/users")
            .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE)
            .defaultHeader("Accept", MediaType.APPLICATION_JSON_VALUE)
            .defaultHeader("Authorization", "Bearer your_token_here")
            .build();

    public Mono<User> getUser(Long id) {
        return webClient.get()
                .uri("/{id}", id)
                .retrieve()
                .bodyToMono(User.class);
    }

    public Flux<User> getAllUsers() {
        return webClient.get()
                .retrieve()
                .bodyToFlux(User.class);
    }

    public Mono<User> createUser(User user) {
        return webClient.post()
                .bodyValue(user)
                .retrieve()
                .bodyToMono(User.class);
    }

    public Mono<Void> updateUser(Long id, User user) {
        return webClient.put()
                .uri("/{id}", id)
                .bodyValue(user)
                .retrieve()
                .bodyToMono(Void.class);
    }

    public Mono<Void> deleteUser(Long id) {
        return webClient.delete()
                .uri("/{id}", id)
                .retrieve()
                .bodyToMono(Void.class);
    }
}
Enter fullscreen mode Exit fullscreen mode

3๏ธโƒฃ FeignClient โ€“ Declarative REST Client

โœ… Best for microservices and clean architecture using Spring Cloud OpenFeign.

โœ๏ธ Step 1: Add dependency

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Enter fullscreen mode Exit fullscreen mode

โœ๏ธ Step 2: Enable Feign support

@SpringBootApplication
@EnableFeignClients
public class Application { }
Enter fullscreen mode Exit fullscreen mode

โœ๏ธ Step 3: Configuration for headers

@Configuration
public class FeignConfig {
    @Bean
    public RequestInterceptor requestInterceptor() {
        return requestTemplate -> {
            requestTemplate.header("Content-Type", "application/json");
            requestTemplate.header("Accept", "application/json");
            requestTemplate.header("Authorization", "Bearer your_token_here");
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

โœ๏ธ Step 4: Define FeignClient interface

@FeignClient(name = "user-client", url = "http://localhost:8081", configuration = FeignConfig.class)
public interface UserFeignClient {
    @GetMapping("/users/{id}")
    User getUser(@PathVariable Long id);

    @GetMapping("/users")
    User[] getAllUsers();

    @PostMapping("/users")
    User createUser(@RequestBody User user);

    @PutMapping("/users/{id}")
    void updateUser(@PathVariable Long id, @RequestBody User user);

    @DeleteMapping("/users/{id}")
    void deleteUser(@PathVariable Long id);
}
Enter fullscreen mode Exit fullscreen mode

โœ๏ธ Step 5: Use the client

@Service
public class UserFeignService {
    private final UserFeignClient client;

    public UserFeignService(UserFeignClient client) {
        this.client = client;
    }

    public User getUser(Long id) {
        return client.getUser(id);
    }

    public User[] getAllUsers() {
        return client.getAllUsers();
    }

    public User createUser(User user) {
        return client.createUser(user);
    }

    public void updateUser(Long id, User user) {
        client.updateUser(id, user);
    }

    public void deleteUser(Long id) {
        client.deleteUser(id);
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿง  When to Use What?

Feature RestTemplate โœ… WebClient โšก FeignClient ๐Ÿค
Synchronous โœ… Yes ๐Ÿšซ No (reactive only) โœ… Yes
Reactive Support ๐Ÿšซ No โœ… Yes ๐Ÿšซ No
Simplicity โœ… Moderate ๐Ÿšซ Complex for blocking โœ… Very Clean
Headers โœ… Manual โœ… Easy โœ… Easy via Config
Best Use Case Legacy apps Reactive APIs Microservices

โœ… Conclusion

You now have a full CRUD implementation for consuming APIs using all three major techniques in Spring Boot:

  • ๐Ÿ’ก RestTemplate for blocking applications
  • ๐Ÿ”„ WebClient for reactive systems
  • ๐Ÿงผ FeignClient for clean declarative usage

๐Ÿ‘‰ All include proper headers, clean coding practices, and a reusable structure.
Use this as your go-to reference when working with any third-party or internal REST APIs.


Top comments (0)