In the Response, i am getting scanAvailable=true when returning flux as ResponseEntity
Asked Answered
A

2

9

I am slightly confused to get the proper response when the user tries to use two rest endpoints with WebClient. I want to use it as asynchronous and non-blocking in the code.

I am returning the Flux from the controller. The code details are as below:

The Controller Class method looks like this:

@RequestMapping(method = RequestMethod.GET, path = "/v1/repos/{userName}", produces = "application/json")
    public ResponseEntity<Flux<GithubRepo>> getUserReposDetails(
            @PathVariable(name="userName",required = true) String userName) throws Exception{
        return new ResponseEntity<>(this.getGitRepos(userName), HttpStatus.OK);
    }

It is calling getGitRepos method. The method details are as below:

private Flux<GithubRepo> getGitRepos(String userName) {
        return webClient.get().uri("/users/{userName}/repos",userName).
                exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(GithubRepo.class)).map(github->{
 github.setBranch(webClient.get()
.uri("/repos/{userName}/{branchName}/branches",userName,github.getBranch())
.retrieve().bodyToFlux(Branch.class).collectList());
                    return github;
                });
    }

And WebClient is:

WebClient webClient =  WebClient.builder().baseUrl("https://api.github.com").
            defaultHeader(HttpHeaders.CONTENT_TYPE, "application/vnd.github.v3+json").build();

The GitHub and Branch Classes are below:

@Data
public class GithubRepo {
    private String name;
    private String ownerLogin;
    private Mono<List<Branch>> branch;
    
    @JsonProperty("owner")
    private void unpackNested(Map<String,String> commit) {
        this.ownerLogin = commit.get("login");
    }
}
@Data
public class Branch {
    
    private String name;
    private Boolean protected;
}

I am getting the JSON response as:

[
  {
    "name": "HelloWorld",
    "ownerLogin": "test",
    "branch": {
      "scanAvailable": true
    }
  },
  {
    "name": "rokehan",
    "ownerLogin": "test",
    "branch": {
      "scanAvailable": true
    }
  },
  {
    "name": "sNews",
    "ownerLogin": "test",
    "branch": {
      "scanAvailable": true
    }
  },
  {
    "name": "Test--01",
    "ownerLogin": "test",
    "branch": {
      "scanAvailable": true
    }
  }
]

I want to get the response as:

[
  {
    "name": "HelloWorld",
    "ownerLogin": "test",
    "branch": [
      {
        "name": "asd",
        "protected": false
      },
      {
        "name": "master",
        "protected": false
      }
    ]
  },
  {
    "name": "rokehan",
    "ownerLogin": "test",
    "branch": [
      {
        "name": "master",
        "protected": false
      }
    ]
  },
  {
    "name": "sNews",
    "ownerLogin": "test",
    "branch": []
  },
  {
    "name": "Test--01",
    "ownerLogin": "test",
    "branch": [
      {
        "name": "master",
        "protected": false
      }
    ]
  }
]

Please help me to resolve this problem.

Agulhas answered 23/5, 2021 at 14:13 Comment(3)
Its because you are trying to serialize Mono<List<Branch> when you construct your GithubRepo you need to have a List<Branch> instead.Vineland
Do a flatMap after collectList and create your object there. Me personally i would have one object that matches the github api, and another object that you return to the calling client. So that the apis can evolve independantly.Vineland
@Vineland : I am pretty new to use that, It is my second day to play with Mono and Flux. I am getting your point, I tried many things but still not able to get the result.Agulhas
V
7

I am not sitting by a computer so i cant check against a compiler (im writing this on mobile)

But the problem is that you are trying to serialize a Mono<List<T>> which means you are trying to send something that might not have been resolved yet. You need to return a List<T>.

private Flux<MyResponse> getGitRepos(String userName) {
    return webClient.get()
                    .uri("/users/{userName}/repos", userName)
                    .exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(GithubRepo.class))
                    .flatMap(github -> {
                        return webClient.get()
                                        .uri("/repos/{userName}/{branchName}/branches", userName, github.getBranch())
                                        .retrieve()
                                            .bodyToFlux(Branch.class)
                                        .collectList())
                                        .flatMap(branches -> {
                                            return Mono.just(new MyResponse(github, branches));
                                        });
        }

I wrote this free hand but you should get the point. Have one class against the github api, and another against your api so you can alter your api freely if the api against github changes.

Vineland answered 23/5, 2021 at 16:22 Comment(0)
A
1

Thanks, @Toerktumlare for helping me. The updated method is:

private Flux<MyResponse> getGitRepos(String userName) {
        return webClient.get()
                                  .uri("/users/{userName}/repos", userName)
                                  .exchangeToFlux(clientResponse -> clientResponse.bodyToFlux(GithubRepo.class))
                                  .flatMap(github -> {
                                      return webClient.get()
                                            .uri("/repos/{userName}/{branchName}/branches", userName, github.getName())
                                            .retrieve()
                                            .bodyToFlux(Branch.class)
                                            .collectList()
                                            .flatMap(branches -> {
                                                return Mono.just(new MyResponse(github, branches));
                                            });
                });
    }
Agulhas answered 23/5, 2021 at 16:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.