1

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.

1 Answer 1

2

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)
2
  • Thanks Adrian, that site you provided is very helpful. I also knew you could use the coding strategy from snake case to camel case. Just wanted to practice using the coding keys, in case I wanted to switch the names. So to me it looks the same, so I guess I'm stuck doing it like this. But thank you for that helpful site. :) Commented Nov 10, 2018 at 4:05
  • Coding keys are a PITA, but sometimes you need to use them. If you’re in a production environment or you’ve got proprietary data, would create your structure the “old fashioned” way, not with that site.
    – Adrian
    Commented Nov 10, 2018 at 4:08

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.