Apollo iOS如何处理GraphQL响应的部分解码失败问题?
解决Apollo Swift数组部分解析失败的容错方案
一、用Apollo内置的数组解码容错配置
Apollo Swift 从0.50.0版本开始,支持让数组解码时自动跳过解析失败的元素,不用改太多代码就能实现需求。具体操作:
初始化ApolloClient的时候,给客户端配置里的解码器加上arrayDecodingHandling设置:
let client = ApolloClient( url: URL(string: "你的GraphQL接口地址")!, configuration: ApolloClient.Configuration( decoder: JSONDecoder().then { $0.arrayDecodingHandling = .ignoreFailedElements } ) )
这么设置后,所有数组类型的字段在解码时,只要单个元素解析失败,就自动跳过,不会连累整个数组甚至整个查询结果失败。
二、针对特定字段做自定义解码(更精准控制)
如果只需要给items数组加容错,或者需要更灵活的处理逻辑,可以自定义解码逻辑:
1. 写个方法处理单个Item的解码
给Apollo生成的GetCollectionsQuery.Data.GetCollections.Item类型加个扩展,让它解码失败时返回nil:
extension GetCollectionsQuery.Data.GetCollections.Item { static func decodeOrNil(from decoder: Decoder) -> Self? { do { return try Self(from: decoder) } catch { print("解析单个Item失败,直接跳过: \(error)") return nil } } }
2. 重写数组字段的解码逻辑
再给GetCollectionsQuery.Data.GetCollections类型加扩展,重写items的解码逻辑,过滤掉解码失败的元素:
extension GetCollectionsQuery.Data.GetCollections: Decodable { enum CodingKeys: String, CodingKey { case items // 这里要把查询里的其他字段都列出来,比如你注释的other fields // ... 其他字段名 } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先解码其他字段,这里要把Apollo生成的其他字段解码逻辑原封不动抄过来 // 比如如果有name字段,就写 self.name = try container.decode(String.self, forKey: .name) // ... 其他字段解码 // 解码items数组,过滤掉失败的元素 self.items = try container.decodeIfPresent([GetCollectionsQuery.Data.GetCollections.Item?].self, forKey: .items)? .compactMap { $0 } ?? [] } }
注意:这种方式要手动维护其他字段的解码代码,后续如果查询字段变了,这里也要同步更新,不然会漏解码。
三、临时改查询字段的可选性(应急用,不推荐)
如果不想折腾解码逻辑,也可以临时修改GraphQL查询,把出错的非空字段的!去掉,改成可选类型:
query mobile_getCollections() { getCollections() { // ... other fields items { activeRange { expires // 原来的Int!改成Int starts // 原来的Int!改成Int } } } }
重新生成Swift代码后,就算后端返回错误格式,只会让expires或starts变成nil,不会导致整个Item或者数组解析失败。但这个方法会改变类型定义,可能影响业务逻辑,只能临时用用。
内容的提问来源于stack exchange,提问作者Liam
相关产品推荐
相关产品推荐

