skip to Main Content

The JSON response is:-

{ 
  "id" = "1"
  "message" = "SUCCESS"
  "data" = "[{"name":"FirstName","office_id":1111,"days_name":"Mon"},
            {"name":"SecondName:,"office_id":1112,"days_name":"Tue"}]"

}

I don’t seems to understand how to approach decoding "data", In data model shall the data be declared as String? and I have been trying to figure out but don’t seem to get any clue and stuck here for a while, if anyone can please shed some light to it, it would help a lot. The only problem I am facing is how to deal with "" double quotes wrapped around data array as shown in above response.

Data model and URLSession code is below:

struct Root : Codable {
    let id : String?
    let message : String?
    let data : String?

    enum CodingKeys: String, CodingKey {

        case id = "id"
        case message = "message"
        case data = "data"
    }
}

struct insideData: Codable {
    
    let name: String?
    let officeId : Int?
    let daysName: String?
    
    enum CodingKeys: String, CodingKey {

        case name = "name"
        case officeId = "office_id"
        case daysName = "days_name"
   
    }
}

URLSession.shared.dataTask(with: url!) { (responseData, httpUrlResponse , error) in
        
    if(error == nil && responseData != nil && responseData?.count != 0){
        
        let decoder = JSONDecoder()
        
        do{
            
            let result = try decoder.decode(Root.self, from: responseData!)
            print(result.data!)

        }
        catch let error {
            debugPrint("Error occured while decoding = (error.localizedDescription)")
        }
    }
}.resume()


I save result.data! in a new variable and convert it to data and again use JSONDecoder but now with insideData.self struct but don’t get desired output, not getting mapped with keys inside insideData struct.
I am just getting started with learning networking in swift so please pardon me for silly mistakes.

2

Answers


  1. data value is JSON with JSON, ie it’s a JSONString.

    A way to parse it is to parse again the JSON String. To do so, you need to override init(from decoder:) of Root.

    Let’s first fix your JSON which isn’t valid, to be able to use it in Playgrounds.

    let jsonString = #"""
    {
        "id": "1",
        "message": "SUCCESS",
        "data": "[{"name":"FirstName","office_id":1111,"days_name":"Mon"}, {"name":"SecondName:", "office_id":1112,"days_name":"Tue"}]"
    }
    """#
    

    Then, change data: let data : [InsideData]

    You could then:

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decodeIfPresent(String.self, forKey: .id)
        self.message = try container.decodeIfPresent(String.self, forKey: .message)
        guard let dataString = try container.decodeIfPresent(String.self, forKey: .data) else {
            self.data = []
            return
        }
        self.data = try JSONDecoder().decode([InsideData].self, from: Data(dataString.utf8))
    }
    

    If you don’t like creating a new decoder, you can pass one in userInfo of the decoder:

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try container.decodeIfPresent(String.self, forKey: .id)
        self.message = try container.decodeIfPresent(String.self, forKey: .message)
        guard let dataString = try container.decodeIfPresent(String.self, forKey: .data) else {
            self.data = []
            return
        }
        guard let insideDecoder = decoder.userInfo[CodingUserInfoKey(rawValue: "InsideDecoder")!] as? JSONDecoder else {
            self.data = []
            return
        }
        self.data = try insideDecoder.decode([InsideData].self, from: Data(dataString.utf8))
    }
    

    Then the root decoding:

    let decoder = JSONDecoder()
    let insideDecoder = JSONDecoder()
    decoder.userInfo = [CodingUserInfoKey(rawValue: "InsideDecoder")!: insideDecoder]
    do {
        let root = try decoder.decode(Root.self, from: Data(jsonString.utf8))
        print(root)
    } catch {
        print("Error: (error)")
    }
    
    Login or Signup to reply.
  2. The provided JSON looks to be invalid.

    1. In json you don’t use the = sign but the : sign between a key and value.
    2. You are missing , behind each value.
    3. There is a typo behind SecondName :, should be ",
    4. It’s weird to have quotes around your data array. It can be easier decoded when you have them removed.

    Suggested JSON changes:

    {
      "id": "1",
      "message": "SUCCESS",
      "data": [
        {"name":"FirstName","office_id":1111,"days_name":"Mon"},
        {"name":"SecondName","office_id":1112,"days_name":"Tue"}
      ]
    }
    

    I’ve tested decoding this json in Playground and it seems to work:

    struct DataEntity: Decodable {
        let name: String
        let officeId: Int
        let daysName: String
        
        enum CodingKeys: String, CodingKey {
            case name = "name"
            case officeId = "office_id"
            case daysName = "days_name"
        }
    }
    
    struct RootEntity: Decodable {
        let id: String
        let message: String
        let data: [DataEntity]
    }
    
    struct Mapper {
        func map(json: String) -> RootEntity {
            guard let rootJsonData = json.data(using: .utf8) else {
                fatalError("Couldn't convert json string to data")
            }
            do {
                let rootEntity = try JSONDecoder().decode(RootEntity.self, from: rootJsonData)
                return rootEntity
            } catch let error {
                fatalError(error.localizedDescription)
            }
        }
    }
    
    let jsonToDecode = """
    {
      "id": "1",
      "message": "SUCCESS",
      "data": [
        {"name":"FirstName","office_id":1111,"days_name":"Mon"},
        {"name":"SecondName","office_id":1112,"days_name":"Tue"}
      ]
    }
    """
    
    let rootEntity = Mapper().map(json: jsonToDecode)
    print(rootEntity)
    

    Print output:

    RootEntity(id: "1", message: "SUCCESS", data: [DataEntity(name: "FirstName", officeId: 1111, daysName: "Mon"), DataEntity(name: "SecondName", officeId: 1112, daysName: "Tue")])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search