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.
CodePudding user response:
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)")
}
CodePudding user response:
The provided JSON looks to be invalid.
- In json you don't use the
=
sign but the:
sign between a key and value. - You are missing
,
behind each value. - There is a typo behind SecondName
:,
should be",
- 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")])