Spring Boot WebClient PUT Request Example

In this tutorial, we will build an 'Update Employee' REST API and demonstrate how to consume it using WebClient, including passing a request body. 

Spring Boot WebClient PUT Request Example

First, you'll set up a Spring Boot application with a MySQL database to store employee data. Then, you'll create a service to handle data persistence and finally use WebClient to update an employee's data. Let's get started.

Step 1: Set Up the Spring Boot Project with MySQL 

Add the necessary dependencies to your pom.xml:

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

<dependency>
  <groupId>com.mysql</groupId>
  <artifactId>mysql-connector-j</artifactId>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>

Step 2: Configure MySQL Database 

Set up your application.properties or application.yml with your MySQL configuration: 

application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/your_database
spring.datasource.username=your_username
spring.datasource.password=your_password

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

Replace your_database, your_username, and your_password with your actual MySQL database name and credentials.

Step 3: Create the Employee Entity and Repository 

Define an Employee entity and a corresponding repository. 

Employee.java:

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
@Table(name = "employees")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String department;
    
    // Constructors, getters, and setters can be omitted for brevity (use Lombok)
}

EmployeeRepository.java:

import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    // Custom methods if needed
}

Step 4: Implement the Service Layer 

Create a service to handle CRUD operations. 

EmployeeService.java:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class EmployeeService {

    private final EmployeeRepository employeeRepository;

    @Autowired
    public EmployeeService(EmployeeRepository employeeRepository) {
        this.employeeRepository = employeeRepository;
    }

    public Employee updateEmployee(Long id, Employee employeeDetails) {
        Employee employee = employeeRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Employee not found"));
        employee.setName(employeeDetails.getName());
        employee.setDepartment(employeeDetails.getDepartment());
        return employeeRepository.save(employee);
    }
    
    // Additional service methods
}

Step 5: Create the REST Controller 

Define a controller with a PUT mapping to update an employee. 

EmployeeController.java:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/employees")
public class EmployeeController {

    private final EmployeeService employeeService;

    @Autowired
    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @PutMapping("/{id}")
    public ResponseEntity<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employee) {
        Employee updatedEmployee = employeeService.updateEmployee(id, employee);
        return ResponseEntity.ok(updatedEmployee);
    }
}

Step 6: Configure WebClient

Set up WebClient in your configuration:
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() {
        return WebClient.builder()
                .baseUrl("http://localhost:8080/api/employees")
                .build();
    }
}

Step 7: Use WebClient to Consume the Update API 

With your REST API in place, let's consume it using WebClient. 

WebClientService.java:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@Service
public class WebClientService {

    private final WebClient webClient;

    @Autowired
    public WebClientService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("http://localhost:8080").build();
    }

    public Mono<Employee> updateEmployee(Long id, Employee employee) {
        return webClient.put()
                        .uri("/api/employees/{id}", id)
                        .bodyValue(employee)
                        .retrieve()
                        .bodyToMono(Employee.class);
    }
    
    // Handling errors and other methods can be added as well
}

In this service, the updateEmployee method sends a PUT request to our API endpoint. The bodyValue(employee) sets the request body, and uri method includes path variable substitution. 

Step 8: Calling WebClient Service from the Application 

Finally, you might use the WebClientService from anywhere in your application. A typical example could be a scheduled job or during application startup: 

ApplicationRunner.java:

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class ApplicationRunner implements CommandLineRunner {

    private final WebClientService webClientService;

    public ApplicationRunner(WebClientService webClientService) {
        this.webClientService = webClientService;
    }

    @Override
    public void run(String... args) throws Exception {
        Employee employeeToUpdate = new Employee();
        employeeToUpdate.setName("John Doe Updated");
        employeeToUpdate.setDepartment("Engineering Updated");

        webClientService.updateEmployee(1L, employeeToUpdate)
            .subscribe(
                employee -> System.out.println("Updated Employee: " + employee.getName()),
                error -> System.err.println("Failed to update employee: " + error.getMessage())
            );
    }
}
This ApplicationRunner will execute at the startup of the Spring Boot application, calling the updateEmployee method of WebClientService, and logging the result to the console.

Conclusion

In this blog post, we've created a complete Spring Boot application with a RESTful endpoint for updating employee records in a MySQL database. Furthermore, we've illustrated how to consume this endpoint with Spring Boot's WebClient, performing a PUT request with an employee object as the request body. The reactive nature of WebClient ensures that we're ready for scalable and non-blocking operations, essential for today's high-performance applications.

Comments