【问题标题】:Making an API call using WebClient inside of a Controller在 Controller 中使用 WebClient 进行 API 调用
【发布时间】:2021-08-14 00:37:11
【问题描述】:

所以我有一个简单的@RestController 端点,我想在其中使用 WebClient 进行 API 调用,然后获取从该调用中获得的数据,进行更多 API 调用、处理数据和最终返回一些基于所有这些的数据......

然而,这整个反应式的事情让我很困惑。我知道如何使用RestTemplate 以旧方式执行此操作,没问题......我想这正是使用block() 等待客户端完成然后我可以使用它的时候数据,但显然这在“反应式”控制器中是不允许的!

我创建了一个自定义 POJO (ExternalApiResponse),它与来自 API 的 JSON 数据响应相匹配,这似乎工作正常...以下代码可以正常工作,并且完美地响应来自的 JSON 数据API 调用并在从外部 API 获取后在浏览器中显示...

这个ExternalApiResponse 实际上只包含另一个 POJO 的一个 List,因为 API 调用的结果格式类似于 { [ ] }(有没有更好的方法来做到这一点?),这意味着一个数组包含在一个对象...我不想只返回 API 结果,我想遍历它们,甚至对最初返回的 API 结果中的每个元素进行额外的 API 调用(在其他地方),然后返回一个具有已处理!

@RestController
@RequestMapping
public class Controller {
  @RequestMapping("/{id}")
  public Mono<ExternalApiResponse> queryApi(@PathVariable String id) {
    Mono<ExternalApiResponse> response = webClientBuilder.build()
    .get()
    .uri(uri)
    .accept(MediaType.APPLICATION_JSON)
    .retrieve()
    .bodyToMono(ExternalApiResponse.class)
    
    return response;

  }
}

我认为有一种更合适的方式来构建它,但我不确定。非常感谢任何潜在客户!

【问题讨论】:

  • 我认为解决方案是使用map()flatMap(),但我所做的每一次尝试都失败了! ://
  • 对单声道进行平面映射,从对象中获取列表将其放入 Flux.fromIterable,然后再次对从通量发出的每个项目进行平面映射。在该 flatMap 中,为每个项目执行一个新的 webclient 调用。
  • 使用flatMap 将简单地合并/展平您在此过程中检索到的每个响应。但是,您说“进行更多的 API 调用,处理数据,并最终根据所有这些返回一些数据” - 这意味着 flatMap 实际上可能是错误的方法。也许你应该简单地subscribe() 到 Mono,然后进行 API 调用,subscribe() 到那个,然后继续下去,直到你处理数据。最后从每个subscribe() 返回结果,让它一直冒泡返回客户端。
  • 我在读到 subscribe 不应该在这里使用,这不正确吗?我在这里严重不知道正确的语法,我无法弄清楚如何使用 flatMap 或 map 从单个响应中提取列表(或数组,我都尝试过)!一个小的语法示例将大大帮助我度过美好的一天!
  • 这似乎可以将集合提取到它自己的 CollectionType Mono... Mono collect = response.map(c -> c.getCollection());但是我不知道该怎么做才能遍历它们!

标签: java spring-boot spring-webflux spring-webclient


【解决方案1】:
@RequestMapping("/{id}")
public Mono<MyApiResponse> queryApi(@PathVariable String id) {
    return webClientBuilder
        .build()
        .get()
        .uri(uri)
        .accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .bodyToMono(ExternalApiResponse.class)
        .flatMapIterable(externalApiResponse -> externalApiResponse.getList()) // switch to flux
        .flatMap(item -> process(item)) // process each item individually
        .collectList() // collect processed items into a list to wrap them
        .map(processedItems -> new MyApiResponse(processedItems)); // wrap
}

private Mono<ProcessedItem> process(Item item) {
    // todo
}

private static class ExternalApiResponse {
    List<Item> list;
}

private static class MyApiResponse {
    List<ProcessedItem> processedItems;
}

【讨论】:

    猜你喜欢
    • 2020-03-22
    • 1970-01-01
    • 2018-06-11
    • 1970-01-01
    • 2021-10-03
    • 2018-09-16
    • 2019-08-16
    • 2020-03-16
    • 2011-03-17
    相关资源
    最近更新 更多