Luis F Ramirez
Luis F Ramirez

Reputation: 168

Parsing nested JSON using Codable

So I'm trying to parse JSON that looks something like this using Codable in Swift.

{
"abilities": [
    {
        "ability": {
            "name": "chlorophyll",
            "url": "https://pokeapi.co/api/v2/ability/34/"
        },
        "is_hidden": true,
        "slot": 3
    },
    {
        "ability": {
            "name": "overgrow",
            "url": "https://pokeapi.co/api/v2/ability/65/"
        },
        "is_hidden": false,
        "slot": 1
    }
],
"name": "SomeRandomName"
}

Now it gets confusing when you're trying to get nested data. Now I'm trying to get the name, which is easy. I'm also trying to get the ability name, this is where its gets complicated for me. After some research this is what I came up with.

class Pokemon: Codable {

struct Ability: Codable {
    var isHidden: Bool

    struct AbilityObject: Codable {
        var name: String
        var url: String
    }

    var ability: AbilityObject

    private enum CodingKeys: String, CodingKey {
        case isHidden = "is_hidden"
        case ability
    }
}

var name: String
var abilities: [Ability]
}

Now is there any better way in doing this, or am I stuck doing it like this.

Upvotes: 1

Views: 421

Answers (1)

Adrian
Adrian

Reputation: 16735

Grab your JSON response and dump it in this site.

It'll generate these structs without Codable. Add Codable so they look like this:

struct Pokemon: Codable {
    let abilities: [AbilityElement]
    let name: String

    struct AbilityElement: Codable {
        let ability: Ability
        let isHidden: Bool
        let slot: Int

        struct Ability: Codable {
            let name: String
            let url: String
        }
    }
}

For keys with snake_case, you can just declare a JSONDecoder and specify the keyDecodingStrategy as .convertFromSnakeCase. No need to muck around with coding keys if you're just converting from snake case. You only need them if you're renaming keys.

If you have other situations where you need to create custom coding keys for your responses or alter key names, this page should prove helpful.

You can dump this in a playground and play around with it:

let jsonResponse = """
{
    "abilities": [
    {
        "ability": {
        "name": "chlorophyll",
        "url": "https://pokeapi.co/api/v2/ability/34/"
    },
    "is_hidden": true,
    "slot": 3
    },
    {
    "ability": {
        "name": "overgrow",
        "url": "https://pokeapi.co/api/v2/ability/65/"
    },
    "is_hidden": false,
    "slot": 1
    }
    ],
    "name": "SomeRandomName"
}
"""

struct Pokemon: Codable {
    let abilities: [AbilityElement]
    let name: String

    struct AbilityElement: Codable {
        let ability: Ability
        let isHidden: Bool
        let slot: Int

        struct Ability: Codable {
            let name: String
            let url: String
        }
    }
}

var pokemon: Pokemon?

do {
    let jsonDecoder = JSONDecoder()
    jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
    if let data = jsonResponse.data(using: .utf8) {
        pokemon = try jsonDecoder.decode(Pokemon.self, from: data)
    }
} catch {
    print("Something went horribly wrong:", error.localizedDescription)
}

print(pokemon)

Upvotes: 2

Related Questions