WebClient in Spring Boot

WebClient is the non-blocking, reactive HTTP client in Spring WebFlux, introduced as a replacement for RestTemplate (though RestTemplate is still supported for blocking I/O).


1. Add Dependency

If you’re using Maven, add:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

For Gradle:

implementation 'org.springframework.boot:spring-boot-starter-webflux'

2. Create a WebClient Bean

You can configure a reusable WebClient bean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder.baseUrl("https://jsonplaceholder.typicode.com")
                      .build();
    }
}

3. Service Example

Example: Fetch posts from JSONPlaceholder API (https://jsonplaceholder.typicode.com/posts).

import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
public class PostService {

    private final WebClient webClient;

    public PostService(WebClient webClient) {
        this.webClient = webClient;
    }

    // Get all posts (non-blocking)
    public Flux<Post> getAllPosts() {
        return webClient.get()
                        .uri("/posts")
                        .retrieve()
                        .bodyToFlux(Post.class);
    }

    // Get single post by ID
    public Mono<Post> getPostById(int id) {
        return webClient.get()
                        .uri("/posts/{id}", id)
                        .retrieve()
                        .bodyToMono(Post.class);
    }
}

4. DTO Example

public class Post {
    private int userId;
    private int id;
    private String title;
    private String body;

    // getters and setters
}

5. Controller Example

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
public class PostController {

    private final PostService postService;

    public PostController(PostService postService) {
        this.postService = postService;
    }

    @GetMapping("/posts")
    public Flux<Post> getPosts() {
        return postService.getAllPosts();
    }

    @GetMapping("/posts/{id}")
    public Mono<Post> getPost(@PathVariable int id) {
        return postService.getPostById(id);
    }
}

6. Example Requests

  • GET http://localhost:8080/posts → returns list of posts.
  • GET http://localhost:8080/posts/1 → returns post with ID 1.

👉 This is the reactive way (non-blocking).
If you want synchronous (blocking), you can just call .block() on the result, e.g.:

Post post = webClient.get()
                     .uri("/posts/{id}", 1)
                     .retrieve()
                     .bodyToMono(Post.class)
                     .block();

Leave a Reply