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();