The Power of webclient WebClient:** We use `WebClient` to make e Customer and Account APIs. *`Mono`:** We use `Mono` from Project
- Mark Kendall
- Feb 23
- 4 min read
Alright, let's break down how you'd achieve this in Spring Boot, calling your Customer and Account APIs, combining the results, and creating a DTO for your React app.
Assumptions:
*Customer API:**
* Fields: `customerId`, `firstName`, `lastName`, `email`
*Account API:**
* Fields: `accountId`, `customerId`, `accountNumber`, `balance`
* You're using Spring WebClient (recommended for modern Spring Boot applications) for making HTTP requests.
* You're using Jackson for JSON serialization/deserialization.
1. Define Your Data Transfer Objects (DTOs):
```java
public class CustomerDto {
private String customerId;
private String firstName;
private String lastName;
private String email;
// Constructors, getters, setters...
}
public class AccountDto {
private String accountId;
private String customerId;
private String accountNumber;
private double balance;
// Constructors, getters, setters...
}
public class CombinedCustomerAccountDto {
private String customerId;
private String firstName;
private String lastName;
private String email;
private String accountNumber;
private double balance;
// Constructors, getters, setters...
}
```
2. Create a Service to Call the APIs and Combine Data:
```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 CustomerAccountService {
private final WebClient webClient;
private final String baseUrl = "www.mark.com"; // Your base URL
@Autowired
public CustomerAccountService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl(baseUrl).build();
}
public Mono<CombinedCustomerAccountDto> getCombinedCustomerAccount(String customerId) {
Mono<CustomerDto> customerMono = webClient.get()
.uri("/customers/{customerId}", customerId)
.retrieve()
.bodyToMono(CustomerDto.class);
Mono<AccountDto> accountMono = webClient.get()
.uri("/accounts/{customerId}", customerId)
.retrieve()
.bodyToMono(AccountDto.class);
return Mono.zip(customerMono, accountMono, (customer, account) -> {
CombinedCustomerAccountDto combined = new CombinedCustomerAccountDto();
combined.setCustomerId(customer.getCustomerId());
combined.setFirstName(customer.getFirstName());
combined.setLastName(customer.getLastName());
combined.setEmail(customer.getEmail());
combined.setAccountNumber(account.getAccountNumber());
combined.setBalance(account.getBalance());
return combined;
});
}
}
```
3. Create a Controller to Expose the Combined Data:
```java
import org.springframework.beans.factory.annotation.Autowired;
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.Mono;
@RestController
public class CustomerAccountController {
private final CustomerAccountService customerAccountService;
@Autowired
public CustomerAccountController(CustomerAccountService customerAccountService) {
this.customerAccountService = customerAccountService;
}
@GetMapping("/combined/{customerId}")
public Mono<CombinedCustomerAccountDto> getCombinedData(@PathVariable String customerId) {
return customerAccountService.getCombinedCustomerAccount(customerId);
}
}
```
4. Configure WebClient:
In your main Spring Boot application class or a configuration class, create a `WebClient.Builder` bean:
```java
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.Builder webClientBuilder() {
return WebClient.builder();
}
}
```
Explanation:
*DTOs:** We create DTOs to represent the data structures of the Customer, Account, and combined data.
*WebClient:** We use `WebClient` to make e Customer and Account APIs.
*`Mono`:** We use `Mono` from Project Reactor to handle asynchronous operations.
*`Mono.zip()`:** This operator combines the results of the two `Mono`s (customer and account data) into a single `Mono` of `CombinedCustomerAccountDto`.
*Service:** The `CustomerAccountService` encapsulates the logic for calling the APIs and combining the data.
*Controller:** The `CustomerAccountController` exposes a REST endpoint (`/combined/{customerId}`) that returns the combined data.
*Configuration:** The `WebClientConfig` creates a `WebClient.Builder` bean, which is used to create the `WebClient` instance.
How it Works:
1. The React app makes a request to `/combined/{customerId}`.
2. The `CustomerAccountController` calls the `CustomerAccountService`.
3. The `CustomerAccountService` uses `WebClient` to make requests to the Customer and Account APIs.
4. `Mono.zip()` waits for both API calls to complete, then combines the results into a `CombinedCustomerAccountDto`.
5. The `CombinedCustomerAccountDto` is returned to the React app as JSON.
Important Notes:
*Error Handling:** Add proper error handling (e.g., `onErrorResume`, `onErrorMap`) to handle API failures.
*Security:** If your APIs require authentication, configure `WebClient` with the necessary authentication headers.
*Testing:** Write unit and integration tests to ensure your code works correctly.
*Dependencies:** Ensure you have the necessary Spring WebFlux dependencies in your `pom.xml` or `build.gradle`.
*URL's:** Make sure that the URL's that are within the service class are correct, and that they match the actual URL's of your microservices.
*Logging:** Add logging to track the flow of requests and responses.
This provides a solid starting point for calling your microservices, combining the data, and sending it to your React app. Remember to adapt the code to your specific requirements and add necessary error handling and security measures.

Comments