Decoding JSON with generic codingKeys

How to decode JSON with dynamic key base on generic T?
I got an error: Raw value for enum case must be a literal.

struct GraphQLActionResp<T: GraphQLAction>: GraphQLDecodable {

    var root: RespData?

    enum CodingKeys: String, CodingKey {
        case root = T.rootKey // Raw value for enum case must be a literal
    }

    struct RespData: Decodable {
        var isOk: Bool
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.root = try container.decode(RespData.self, forKey: CodingKeys.root)
    }
}

protocol GraphQLAction: Decodable {

    static var rootKey: String { get }
}

struct AAction: GraphQLAction {
    static var rootKey: String {
        return "A"
    }
}

struct BAction: GraphQLAction {
    static var rootKey: String {
        return "B"
    }
}

It's pretty simple: Don't use an enum for your coding keys. Just use a struct that conforms to the CodingKey protocol:

struct GraphQLActionResp<T: GraphQLAction>: Codable {

    var root: RespData?

    struct CodingKeys: CodingKey {
        
        init?(intValue: Int) {
            return nil
        }
        
        init(stringValue: String) {
            self.stringValue = stringValue
        }
        
        let stringValue: String
        let intValue: Int? = nil
        
        static var root: Self { Self(stringValue: T.rootKey) }
        
    }

    struct RespData: Codable {
        var isOk: Bool
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.root = try container.decode(RespData.self, forKey: CodingKeys.root)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.root, forKey: .root)
    }

}

protocol GraphQLAction: Decodable {

    static var rootKey: String { get }
}

struct AAction: GraphQLAction {
    static var rootKey: String {
        return "A"
    }
}

struct BAction: GraphQLAction {
    static var rootKey: String {
        return "B"
    }
}
1 Like
Terms of Service

Privacy Policy

Cookie Policy