skip to Main Content

I have a json response which is something like this:

"Details": {
        "Attachments": [],
        "place": {
          "destination": {
            "type": "international",
            "Id": "superman",
            "locationType": "City",
            "Name": "Kent"
          },
          "package": 52.32,
          "description": "Dinner"
        }
      }
    }

in this response all the parameters in destination are optional except for type, so i m handling this response like this:

public struct Destination: Decodable, Equatable {
    public let Id: String?
    public let Name: String?
    public let city: String?
    public let locationType: String?
    public let pinCode: String?
    public let country: String?
    public let state: String?
    public let currency: String?
    public let language: String?
    public let type: Type
}

as all the parameters are optional and based upto the type i ll be getting only few of these parameters in response.
like –

type: "international",
       country: "US"
       id: "5",
       currency: "Dollar"

is there any way i can write this in an enum:

enum Destination {
case international(country: String, id: String, currency: String)
case national(state: String, language: String, pincode: String)
}

can anyone please answer how should i start with this approach.Thanks

3

Answers


  1. you have to write enum such as

    Enum CodingKeys: String, CodingKey {
    
        case Id, Name, city, locationType, pinCode, country, state, currency, language = String?
    
        case type = Type
    }
    
    Login or Signup to reply.
  2. struct Details: Decodable {
    
      enum CodingKeys: String, CodingKey {
          case Attachments, place
      }
    
      let Attachments: Array?
        let place: Place?
    
    }
    
    struct Place: Decodable {
      let destination: Destination?
        let package: Double?
        let description: String?
    }
    
    struct Destination: Decodable {
      let type, Id, locationType, Name: String?
    }
    
    Login or Signup to reply.
  3. Since Swift 5.5 enums with associated values have Codable synthesis, but this requires the top-level container to contain a single key that matches the name of the enum case. In your case you what a value inside the container to determine the case, so the only solution is to write the init(from decoder: Decoder) yourself, decode all the associated values and then return the enum value.

    Something like this would work:

    public struct Place: Decodable {
        var destination: Destination
    }
    
    enum Destination: Decodable {
        case international(country: String?, Id: String?, currency: String?)
        case national(state: String?, language: String?, pincode: String?)
    
        enum CodingKeys: String, CodingKey {
            case type
            case country
            case Id
            case currency
        }
    
        init(from decoder: Decoder) throws {
            var container = try decoder.container(keyedBy: CodingKeys.self)
            let type = try container.decode(String.self, forKey: .type)
            let country = try container.decodeIfPresent(String.self, forKey: .country)
            let Id = try container.decodeIfPresent(String.self, forKey: .Id)
            let currency = try container.decodeIfPresent(String.self, forKey: .currency)
    
            switch type {
            case "international":
                self = Destination.international(country: country, Id: Id, currency: currency)
            case "national":
                fatalError("not supported yet")
                () // similary
            default:
                fatalError("not supported yet")
                () // throw an decoding error
            }
        }
    }
    

    The above would work with the JSON you have provided:

    let json = """ {
            "destination": {
                "type": "international",
                "Id": "superman",
                "country": "City",
                "currency": "Kent"
            } } """ 
    
        do {
             let data = try JSONDecoder().decode(Place.self, from: json.data(using: .utf8)!) 
       } 
       catch {
             print("error (error)") 
       }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search