Swift中如何解码GraphQL返回的Any类型(自动生成Apollo查询)
解决Apollo Client解码GraphQL Any类型的问题
问题核心是自动生成的Apollo代码将GraphQL的Any类型硬映射为Swift的String,但后端实际返回Bool、Int、Float等其他基础类型,导致类型不匹配解码失败。以下是三种可行的解决方法:
方法1:自定义GraphQL标量解码器
注册自定义的Any标量处理逻辑,让Apollo能正确解析所有基础类型:
import Apollo // 扩展JSONDecodable处理Any类型解码 extension JSONDecodable where Self == Any { public static func decode(jsonValue value: JSONValue) throws -> Self { switch value { case let string as String: return string case let bool as Bool: return bool case let int as Int: return int case let float as Float: return float default: throw JSONDecodingError.couldNotConvert(value: value, to: Any.self) } } } // 扩展JSONEncodable处理Any类型编码 extension JSONEncodable where Self == Any { public func encodeToJSONValue() throws -> JSONValue { switch self { case let string as String: return string case let bool as Bool: return bool case let int as Int: return int case let float as Float: return float default: throw JSONEncodingError.couldNotEncode(value: self) } } } // 初始化Apollo客户端时注册标量映射 let apolloClient = ApolloClient( networkTransport: RequestChainNetworkTransport( interceptorProvider: DefaultInterceptorProvider(client: nil), endpointURL: URL(string: "你的GraphQL接口地址")! ), store: ApolloStore(), scalarMapping: [ "Any": Any.self ] )
方法2:修改自动生成代码的模板
如果使用Apollo CLI自动生成代码,修改模板文件(如API.swift.gyb),将Any类型的映射从String改为Any或自定义类型:
{% if field.type.name == "Any" %} public typealias {{ field.name.pascalCase }} = Any {% else %} // 保留原有类型映射逻辑 {% endif %}
修改后重新生成代码,字段类型会直接使用Swift的Any,配合方法1的解码器即可正常解析。
方法3:用枚举封装所有可能类型
定义枚举覆盖所有后端可能返回的类型,替代自动生成的String类型,类型更安全:
import Apollo enum GraphQLAnyValue: JSONDecodable, JSONEncodable { case string(String) case bool(Bool) case int(Int) case float(Float) static func decode(jsonValue value: JSONValue) throws -> Self { switch value { case let s as String: return .string(s) case let b as Bool: return .bool(b) case let i as Int: return .int(i) case let f as Float: return .float(f) default: throw JSONDecodingError.couldNotConvert(value: value, to: GraphQLAnyValue.self) } } func encodeToJSONValue() throws -> JSONValue { switch self { case .string(let s): return s case .bool(let b): return b case .int(let i): return i case .float(let f): return f } } }
然后在Apollo客户端初始化时,将"Any"标量映射到GraphQLAnyValue.self,自动生成的代码中对应字段会变成GraphQLAnyValue类型,解码时可通过枚举判断具体类型。
注意事项
- 若使用自动生成代码,每次重新生成前要确保模板修改未被覆盖;
- 处理
Any类型时,业务逻辑中需做好类型判断,避免后续转换出错。
内容的提问来源于stack exchange,提问作者zdravko zdravkin
相关产品推荐
相关产品推荐

