scgough
scgough

Reputation: 5252

Converting API JSON data to a Swift struct

I am using Swift for the first time and I'd like to be able to process some info from an API response into a usable Swift object.

I have (for example) the following data coming back from my API:

{
    data: [{
       id: 1,
       name: "Fred",
       info: {
           faveColor: "red",
           faveShow: "Game of Thrones",
           faveIceCream: "Chocolate",
           faveSport: "Hockey",
       },
       age: "28",
       location: "The Moon",
    },{
        ...
    }]
}

In swift I have the data coming back from the API. I get the first object and I'm converting it and accessing it like so:

let json = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
let dataParentNode = json["data"] as! [[String:Any]]
let firstObject = dataParentNode[0]

let _id = firstObject["id"] as? String ?? "0"
let _name = firstObject["name"] as? String ?? "Unknown"

This is fine until I want to start processing the sub-objects belonging to the first object so I came up with the following structs to try and make this cleaner.

Please note - I don't need to process all of the JSON data coming back so I want to convert it to what I need in the structs

struct PersonInfo : Codable {
    let faveColor: String?
    let faveShow: String?
}

struct Person : Codable {
   let id: String?
   let name: String?
   let info: PersonInfo?
}

When I take this:

let json = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
let dataParentNode = json["data"] as! [[String:Any]]
let firstObject = dataParentNode[0]

and then try to convert firstObject to Person or firstObject["info"] to PersonInfo I can't seem to get it to work (I get nil).

let personInfo = firstObject["info"] as? PersonInfo

Can anyone advise please? I just need to get my head around taking API response data and mapping it to a given struct (with sub-objects) ignoring the keys I don't need.

Upvotes: 1

Views: 672

Answers (1)

gcharita
gcharita

Reputation: 8347

You can simply use decode(_:from:) function of JSONDecoder for this:

let decoder = JSONDecoder()
do {
    let decoded = try decoder.decode([String: [Person]].self, from: data)
    let firstObject = decoded["data"]?.first
} catch {
    print(error)
}

Even better you can add another struct to you model like this:

struct PersonsData: Codable {
    let data: [Person]
}

And map your JSON using that type:

let decoder = JSONDecoder()
do {
    let decoded = try decoder.decode(PersonsData.self, from: data)
    let firstObject = decoded.data.first
} catch {
    print(error)
}

Update: Your Person struct might need a little change, because the id property is integer in your JSON.

So, it will end up like this:

struct Person : Codable {
   let id: Int?
   let name: String?
   let info: PersonInfo?
}

Upvotes: 1

Related Questions