I'm a beginner on asynchronous Java programming and I'm trying to understand how to properly use Mutiny for a Quarkus application which has a Client that sends requests to an external API. This client has two methods that return Uni. Those are the following:
@POST
@Path("/repos/{owner}/{repo}/forks")
Uni<Response> createFork(@HeaderParam("Authorization") String authorization,
@PathParam("owner") String owner,
@PathParam("repo") String repo,
String json);`
@POST
@Path("/repos/{owner}/{repo}/transfer")
Uni<Response> transferRepoOwnership(@HeaderParam("Authorization") String authorization, @PathParam("owner") String owner, @PathParam("repo") String repo, String json);
These were tested and the calls to the API are working just fine. In my service class, I'm trying to use Mutiny to chain these two operations, that is, I want to create a fork and then, after the fork is created, I want to transfer the ownership of the repository... I've tried different approaches and I actually managed to chain these operations and execute them: the problem is, in the "callback" of the second call, I can't access the response to process the data. This is my business logic:
type public Uni<Response> beginChallengeWorkflow(String user, String parentRepoId) {
// Check if the challenge exists, that is,
// if the repo to be forked exists
Optional<Challenge> parentChallenge = challengeRepository.findById(parentRepoId);
if (parentChallenge.isEmpty()) {
return Uni.createFrom().item(Response.status(Response.Status.NOT_FOUND)
.entity("The challenge with the specified id doesn't exist!")
.build());
}
// Check if user has already started the challenge
Optional<Challenge> startedChallenge = challengeRepository.findByOwnerAndParentId(user, parentRepoId);
if (startedChallenge.isPresent()) {
return Uni.createFrom().item(Response.status(Response.Status.CONFLICT)
.entity("The user has already started the challenge!")
.build());
}
// User has not started challenge yet, so we want to fork the challenge repo
// and transfer ownership to user
String challengeCreator = parentChallenge.get().getOwnerUsername();
String parentRepoName = parentChallenge.get().getName();
String childRepoName = UUID.randomUUID().toString().substring(0,10) + "-" + user + "-" + parentRepoId;
Uni<Response> forkUni = forkRepository(challengeCreator, parentRepoName, childRepoName)
.onItem().transform(response -> {
if (response.getStatus() != 202) {
throw new RuntimeException("Failed to fork the 'master' challenge PK");
}
return response;
});
Uni<Response> transferUni = transferRepositoryOwnership(user, "root", childRepoName)
.onItem().transform(response -> {
if (response.getStatus() != 202) {
throw new RuntimeException("Failed to transfer ownership of the repo to the user");
}
else{
// Save Challenge entity
// HERE IS WHERE I WANTED TO ACCESS THE RESPONSE
// BUT I CAN'T
// System.out.println(response.getEntity().toString()) causes exception:
// Cannot invoke "Object.toString()" because the return
// value of "javax.ws.rs.core.Response.getEntity()" is null
}
return response;
});
return forkUni.chain(() -> transferUni);
}
I've tried also:
forkRepository(challengeCreator, parentRepoName, childRepoName).onItem().transformToUni( response1 -> {
if (response1.getStatus() != 202) {
throw new RuntimeException("Failed to fork the 'master' challenge PK");
}
return transferRepositoryOwnership(user, "root", childRepoName);
}).subscribe().with(response2 -> {
// response2 is null... I can't access it
});
The strangest thing is that when I call this method from my controller, the endpoint returns the response as I wanted, but I can't access it inside the "callback"... I'm used to asynchronous programming in JavaScript/NodeJS where I could easily access the responses inside the callbacks and I don't understand why is it so complicated to do the same with Mutiny.
Thank you for your attention!
I've tried to chain calls to an external API using Mutiny in a Quarkus application and despite managing to execute the chained operations, I can't access the response in the callback...
Edit: I've added some checks in the second callback to see if there was any response at all at that point:
// Log response status code and headers
System.out.println(response.getStatus());
System.out.println(response.getHeaders());
if (!response.hasEntity()) {
throw new RuntimeException("Response body is empty");
}
else {
// Process response body
String responseBody = response.getEntity().toString();
System.out.println(responseBody);
// ...
}
The status of the response is 202, and the headers are: [Cache-Control=max-age=0, private, must-revalidate, no-transform,Connection=keep-alive,Content-Type=application/json;charset=utf-8,Date=Tue, 25 Apr 2023 11:12:42 GMT,Transfer-Encoding=chunked,X-Content-Type-Options=nosniff,X-Frame-Options=SAMEORIGIN]
But response.getEntity() is null!