You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 15:50:49