The first request is sent asynchronously, then the id value is taken from the response to the first request and used in the second asynchronous request. And then both responses to request 1 and request 2 are combined. The example below works, but the code looks so clunky. Is there a better, shorter way to implement this? Maybe a separate class should be created for 'new Callback()' or what would improve the code? The process in short - everything happens asynchronously:
- Send POST request 1
- Use the id value from response 1 for request 2
- Send POST request 2
- Combine response 1 and response 2 to the final response of the REST controller
This body is sent to the REST controller endpoint "/combine" via POST method:
{ "userid": 1, "id": 2, "title": "3", "body": "4" }
@RestController
public class CombinationController {
@Autowired CombinationService combinationService;
@PostMapping("/combine")
public CompletableFuture<CombinationBothResponses> combine(
@RequestBody RequestBodyOne requestBodyOne) {
CompletableFuture<CombinationBothResponses> resultCallback = new CompletableFuture<>();
combinationService.sendTwoRequests(requestBodyOne, resultCallback);
return resultCallback;
}
}
@Service
public class CombinationService {
private final Jsonb jsonb = JsonbBuilder.create();
private final OkHttpClient client = new OkHttpClient();
public void sendTwoRequests(
RequestBodyOne requestBodyOne, CompletableFuture<CombinationBothResponses> resultCallback) {
// Create request 1
RequestBody requestBody =
RequestBody.create(jsonb.toJson(requestBodyOne), MediaType.parse("application/json"));
Request request =
new Request.Builder()
.url("https://jsonplaceholder.typicode.com/posts")
.post(requestBody)
.build();
// 1. Send POST request 1
client
.newCall(request)
.enqueue(
new Callback() {
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
throws IOException {
if (response.isSuccessful()) {
final CombinationBothResponses combinationBothResponses =
jsonb.fromJson(response.body().string(), CombinationBothResponses.class);
sendSecondPostRequest(combinationBothResponses, resultCallback);
} else {
resultCallback.completeExceptionally(new RuntimeException());
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
resultCallback.completeExceptionally(e);
}
});
}
private void sendSecondPostRequest(
CombinationBothResponses combinationBothResponses,
CompletableFuture<CombinationBothResponses> resultCallback) {
// 2. Use one value from response 1 for request 2
int valueToBeUsedInRequestBody2 = combinationBothResponses.getId();
RequestBodyTwo requestBodyTwo = new RequestBodyTwo(valueToBeUsedInRequestBody2, "request 2");
// Create request 2
RequestBody requestBody =
RequestBody.create(jsonb.toJson(requestBodyTwo), MediaType.parse("application/json"));
Request request =
new Request.Builder().url("https://reqbin.com/echo/post/json").post(requestBody).build();
// 3. Send POST request 2
client
.newCall(request)
.enqueue(
new Callback() {
@Override
public void onResponse(@NotNull Call call, @NotNull Response response)
throws IOException {
if (response.isSuccessful()) {
final CombinationBothResponses combinationBothResponses2 =
jsonb.fromJson(response.body().string(), CombinationBothResponses.class);
// 4. Combine response 1 and response 2 to the final response of the REST controller
combinationBothResponses.setSuccess(combinationBothResponses2.getSuccess());
resultCallback.complete(combinationBothResponses);
} else {
resultCallback.completeExceptionally(new RuntimeException());
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
resultCallback.completeExceptionally(e);
}
});
}
}
@Data
@NoArgsConstructor
public class RequestBodyOne {
private int userId;
private int id;
private String title;
private String body;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RequestBodyTwo {
private int id;
private String key;
}
@Data
@NoArgsConstructor
public class CombinationBothResponses {
private int userId;
private int id;
private String title;
private String body;
private String success;
}
Response to request 1:
{ "userId": 0, "id": 101, "title": "3", "body": "4" }
Response to request 2:
{"success":"true"}
Combined responses; response of REST controller:
{ "userId": 0, "id": 101, "title": "3", "body": "4", "success": "true" }