【问题标题】:Combine JSON decoding pipeline, when response can be an array or an object at runtime结合 JSON 解码管道,在运行时响应可以是数组或对象
【发布时间】:2020-08-03 22:08:17
【问题描述】:

我有一个 API,它可以返回 JSON 对象的 JSON 数组或单个 JSON 对象。

如何编写处理这种情况的组合发布者管道?

当我将组合解码运算符添加到管道时,我通常会硬编码 JSON 响应的类型:

.decode(type: [MyArrayType].self, decoder: JSONDecoder())
.decode(type: MyObjectType.self, decoder: JSONDecoder())

【问题讨论】:

  • 如果可以,更改 API 以返回一个对象的数组。如果不是这样,我建议在解码阶段通过将解码提升到正确解码自身的父“响应”对象来修复它 - 大概,下游链只想处理一种类型的对象。只有这样,我才会在组合管道中解决它 - 它只是感觉不适合它
  • 感谢@pawello2222 的链接。我会试试的。如果解码数组失败,我确实尝试使用组合 .catch 运算符并手动返回一个 Publishers.Decode 实例,该实例在响应中解码单个对象。但无法弄清楚如何正确获取 Decode 类型的通用签名。它想要一个“上游”类型,我不知道如何获得。再次感谢您的链接。
  • @NewDev 感谢您的评论。我无法更改 API(希望可以)。我正在探索联合的做事方式。而且我有一个可重用的通用组合管道,它可以将任何数组响应解码到发布者,该发布者将该响应数组的元素作为输出值发出。我想扩展该组合管道以处理响应不是数组的情况。但是,当然,正如您所说,它可能是将逻辑移至其他地方的最佳解决方案。不是每个问题都是钉子,只是因为你有一把锤子等:)

标签: json swift combine


【解决方案1】:

绝对可以更新发布者链并尝试解码[SomeDecodable] 的数组,如果失败,则回退到解码SomeDecodable 本身。

模式是将其包装在FlatMap 中,并在其中处理故障。

因此,假设您有一些 upstream 发布者,其输出为 Data 并且失败 Error,并且您正在尝试解码一些通用类型 T: Decodable,这可能是一种解决方法:

upstream
  .flatMap { data in
     Just(data)
       // attempt to decode as [T]
       .decode(type: [T].self, decoder: JSONDecoder())
       // if successful, publish each element one-by-one
       .flatMap { arr -> AnyPublisher<T, Error> in 
           Publishers.Sequence(sequence: arr).eraseToAnyPublisher()
       }
       // if error, attempt to decode as T, possibly failing
       .tryCatch { _ in Just(data).decode(type: T.self, decoder: JSONDecoder()) }
  }
  // this will be an AnyPublisher<T, Error>
  .eraseToAnyPublisher()

【讨论】:

  • 感谢@NewDev 的建议。在 Playground 中尝试过,但我收到“不明确地使用 'flatMap(maxPublishers:_:)'”错误。我在运行 Xcode 12 Beta 的 MacOS 11 Beta 上。这是我正在尝试的代码要点:gist.github.com/weenzeel/50d91b2ba10ffb2d5d0d903ae259d7eb
  • 那是因为您使用的是Just(myObjectJSONData),它的失败为Never,而我的示例假定upstream 的失败为Error。这会为flatMap 创建一个不匹配,它必须将其内部返回故障类型与其上游故障类型匹配。要修复,请更改为 Just(myObjectJSONData).setFailureType(to: Error.self)
  • 合并很难!感谢您的支持。对上面的要点进行了更改,但仍然在第 34 行收到相同的错误“Ambiguous use of 'flatMap(maxPublishers:_:)'”。
  • 如果我在 MacOS 10.15 中运行它,要点就可以了。我相信 MacOS 11 中会出现一些新的 flatMap 重载。也许这就是问题所在?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-17
  • 1970-01-01
相关资源
最近更新 更多