Reputation: 121
I have two api calls from I need to get second api call result based on first api call result after that I need to merger both api call responses let me write here
Api call : https://localhost:8080/projects this is the first api call this result is like below
[ {
"projectId" : 2,
"projectName" : "Hello",
"projectDesc" : "Demo project"
},
{
"projectId" : 3,
"projectName" : "Hello123",
"projectDesc" : "Demo project series"
},
{
"projectId" : 4,
"projectName" : "Hello456",
"projectDesc" : "Demo project repeat"
}
]
Second api call http://localhost:8080/projectId in the sense (http://localhost:8080/2) this result as below
[
{
"teamMember" : "abc",
"teamMemberRole": "Manager"
}
]
Now I need to merge both responses , How I can achieve this using webclient
[
{
"projectId" : 2,
"projectName" : "Hello",
"projectDesc" : "Demo project",
"teamMember" : "abc",
"teamMemberRole" : "Manager"
}
]
Your help is appreciate. Thanks in advance
Upvotes: 1
Views: 1749
Reputation: 508
I think i understand your problem and its pretty common. The key thing which you would like to do is to create a flux of responses where each element is merged with Flux of child response. ie.
Assuming that you have a service class which can get the data for projects and team members for a given project.
getAllProjects getTeamMembers
You can use this to write the resulting function called "getProjectsWithTeamMembers"
@Component
@Slf4j
public class ProjectHandler {
@Autowired
private WebClient webClient;
public Flux<Project> getAllProjects() {
return webClient
.get()
.uri("projects")
.retrieve()
.bodyToFlux(Project.class);
}
public Mono<List<TeamMember>> getTeamMembers(Integer id) {
ParameterizedTypeReference<List<TeamMember>> listParameterizedTypeReference =
new ParameterizedTypeReference<List<TeamMember>>() {
};
return webClient.get()
.uri("" + id)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientResponse ->
Mono.empty()
)
.bodyToMono(listParameterizedTypeReference)
.log();
}
public Flux<Project> getProjectsWithTeamMembers() {
return getAllProjects()
.flatMap(project ->
Mono.zip(Mono.just(project),
getTeamMembers(project.getProjectId()).defaultIfEmpty(new ArrayList<TeamMember>()))
.map(tuple -> {
log.info("data" + tuple.getT2().size());
return
Project.builder().projectId(tuple.getT1().getProjectId())
.projectName(tuple.getT1().getProjectName())
.projectDesc(tuple.getT1().getProjectDesc())
.teamMemberList(tuple.getT2()).build();
}));
}
}
Please note tuple is of
Tuple<Project,List<TeamMember>>
Here what exactly you are doing is that using Mono.zip and passing two things to it
Mono.zip will combine it and create Tuple2 of Project and Team members which you can use to write your mapping code to build the full fledged response.
Hope this helps.
-- Update -- Below is updated code
Config for webclient
@Configuration
public class AppConfig {
@Bean
public WebClient webClient(WebClient.Builder webClientBuilder) {
return webClientBuilder
.baseUrl("http://localhost:3000/")
.defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.build();
}
}
Model classes
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Project {
private Integer projectId;
private String projectName;
private String projectDesc;
private List<TeamMember> teamMemberList;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TeamMember {
private String teamMember;
private String teamMemberRole;
}
And finally the rest controller
@RestController
@Slf4j
public class ProjectController {
@Autowired
private ProjectHandler projectHandler;
@GetMapping(PROJECT_ENDPOINT_V1)
public Flux<Project> getAllProjects() {
return projectHandler.getProjectsWithTeamMembers();
}
}
Upvotes: 1