sudhanshu-shishodia
sudhanshu-shishodia

Reputation: 1108

How to simplify Swift Codable Struct for nested JSON?

I have a json like this.

{
  "connectType": "CALL",
  "connectFrequency": "WEEKLY",
  "status": {
    "status": "On"
  }
}

I am trying to parse it using Codable in Swift. I can think of it like below :

struct Preference : Codable {
    let connectFrequency : String?
    let connectType : String?
    let status : PreferenceStatus?
}

struct PreferenceStatus : Codable {
    let status : String?
}

Now when I have to check status on/off value, I will have to go like obj.status?.status. What I would ideally want is to remove the nesting since its only a single value inside the PreferenceStatus.

Is there a way to define my model like below using the same json :

struct Preference : Codable {
    let connectFrequency : String?
    let connectType : String?
    let status : String?
}

I'm new to Codable paradigm. Please assist. Thanks.

Upvotes: 0

Views: 375

Answers (1)

vadian
vadian

Reputation: 285069

To flatten the structure you have to decode the JSON manually. status can be decoded as enum. connectFrequency and connectType seem to be enums, too.

let jsonString = """
{
  "connectType": "CALL",
  "connectFrequency": "WEEKLY",
  "status": {
    "status": "On"
  }
}
"""

enum Frequency : String, Decodable {
   case hourly = "HOURLY", weekly = "WEEKLY"
}

enum Status : String, Decodable {
   case off = "Off", on = "On"
}

struct Preference : Decodable {
    let connectFrequency : Frequency
    let connectType : String
    let status : Status
    
    private enum CodingKeys : String, CodingKey { case connectFrequency, connectType, status }
    
    init(from decoder : Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        connectFrequency = try container.decode(Frequency.self, forKey: .connectFrequency)
        connectType = try container.decode(String.self, forKey: .connectType)
        let nestedContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .status)
        status = try nestedContainer.decode(Status.self, forKey: .status)
    }
}

let data = Data(jsonString.utf8)

do {
    let result = try JSONDecoder().decode(Preference.self, from: data)
    print(result)
} catch {
    print(error)
}

Upvotes: 1

Related Questions