I am hitting an endpoint that may return one of two different JSONs, depending on whether the user needs to answer a security question:
// possible response (payload) #1
{
"token": "123lknk123kj1n13132"
}
// possible response (payload) #2
{
"securityQuestion": "What is your mother's maiden name?"
}
My goal is to create a model that will decode the JSON differently based on which key is present in the payload (i.e. either "token"
or "securityQuestion"
). Currently, I am getting a parsing error and I don't know why.
I took inspiration from a very well-crafted answer to a previous question on SO. My current code is a modified version of it which (in theory) fits my need. I would like the final version of my code to retain this structure. My code is below:
/**
Enumerates the possible payloads received from Server
- success: Successful payload that contains the user's access token
- securityQuestion: Payload that contains the security question that the user has to answer to receive a token
*/
enum PayloadType: String, Decodable {
case success
case securityQuestion
}
protocol Payload: Decodable { static var payloadType: PayloadType { get } }
/// Model for successful response sent by the server.
struct SuccessfulResponse: Payload {
static let payloadType = PayloadType.success
let token: String
}
/// Model for response sent by the server which includes a security question
struct SecurityQuestionResponse: Payload {
static let payloadType = PayloadType.securityQuestion
let securityQuestion: String
}
/// Model for building a response sent by the server.
struct Response: Decodable {
let data: Payload
let payloadType: PayloadType
init(from decoder: Decoder) throws {
// NOTE*: This part is a little shaky, maybe this is where I am going wrong
let values = try decoder.container(keyedBy: CodingKeys.self)
self.payloadType = try values.decode(PayloadType.self, forKey: .payloadType)
// payloadType will determine how the JSON is decoded
switch self.payloadType
{
case .success:
self.data = try values.decode(SuccessfulResonse.self, forKey: .data)
case .securityQuestion:
self.data = try values.decode(SecurityQuestionResponse.self, forKey: .data)
}
}
private enum CodingKeys: String, CodingKey {
case data
case payloadType
}
}
Before posting this question, I looked at various similar posts (1, 2, 3) but none of them really fit needs.