0

I am working with the Spotify API and having trouble with the data model due to the JSON data being more complex than any other data I've seen via tutorials or courses. How would I make my struct for the "items" in this JSON data? I understand a majority of the parameters, for example, "album_group": String and "available_markets": [String] but I don't understand what to do with "artists", "external_urls", and "images". Any help would be appreciated.

Below is the first "item" from the data.

Side Note When I'm creating my struct do I have to include EVERY parameter shown below for my API call to work?

{
  "href": "https://api.spotify.com/v1/artists/3qiHUAX7zY4Qnjx8TNUzVx/albums?offset=0&limit=20&include_groups=album,single,compilation,appears_on&locale=en-US,en;q=0.9",
  "items": [
    {
      "album_group": "album",
      "album_type": "album",
      "artists": [
        {
          "external_urls": {
            "spotify": "https://open.spotify.com/artist/3qiHUAX7zY4Qnjx8TNUzVx"
          },
          "href": "https://api.spotify.com/v1/artists/3qiHUAX7zY4Qnjx8TNUzVx",
          "id": "3qiHUAX7zY4Qnjx8TNUzVx",
          "name": "Yeat",
          "type": "artist",
          "uri": "spotify:artist:3qiHUAX7zY4Qnjx8TNUzVx"
        }
      ],
      "available_markets": [
        "AD",
        "AE",
        "AG",
        "AL",
        "AM",
        "AO",
        "AR",
        "AT",
        "AU",
        "AZ",
        "BA",
        "BB",
        "BD",
        "BE",
        "BF",
        "BG",
        "BH",
        "BI",
        "BJ",
        "BN",
        "BO",
        "BR",
        "BS",
        "BT",
        "BW",
        "BY",
        "BZ",
        "CA",
        "CD",
        "CG",
        "CH",
        "CI",
        "CL",
        "CM",
        "CO",
        "CR",
        "CV",
        "CY",
        "CZ",
        "DE",
        "DJ",
        "DK",
        "DM",
        "DO",
        "DZ",
        "EC",
        "EE",
        "EG",
        "ES",
        "FI",
        "FJ",
        "FM",
        "FR",
        "GA",
        "GB",
        "GD",
        "GE",
        "GH",
        "GM",
        "GN",
        "GQ",
        "GR",
        "GT",
        "GW",
        "GY",
        "HK",
        "HN",
        "HR",
        "HT",
        "HU",
        "ID",
        "IE",
        "IL",
        "IN",
        "IQ",
        "IS",
        "IT",
        "JM",
        "JO",
        "JP",
        "KE",
        "KG",
        "KH",
        "KI",
        "KM",
        "KN",
        "KR",
        "KW",
        "KZ",
        "LA",
        "LB",
        "LC",
        "LI",
        "LK",
        "LR",
        "LS",
        "LT",
        "LU",
        "LV",
        "LY",
        "MA",
        "MC",
        "MD",
        "ME",
        "MG",
        "MH",
        "MK",
        "ML",
        "MN",
        "MO",
        "MR",
        "MT",
        "MU",
        "MV",
        "MW",
        "MX",
        "MY",
        "MZ",
        "NA",
        "NE",
        "NG",
        "NI",
        "NL",
        "NO",
        "NP",
        "NR",
        "NZ",
        "OM",
        "PA",
        "PE",
        "PG",
        "PH",
        "PK",
        "PL",
        "PS",
        "PT",
        "PW",
        "PY",
        "QA",
        "RO",
        "RS",
        "RU",
        "RW",
        "SA",
        "SB",
        "SC",
        "SE",
        "SG",
        "SI",
        "SK",
        "SL",
        "SM",
        "SN",
        "SR",
        "ST",
        "SV",
        "SZ",
        "TD",
        "TG",
        "TH",
        "TJ",
        "TL",
        "TN",
        "TO",
        "TR",
        "TT",
        "TV",
        "TW",
        "TZ",
        "UA",
        "UG",
        "US",
        "UY",
        "UZ",
        "VC",
        "VE",
        "VN",
        "VU",
        "WS",
        "XK",
        "ZA",
        "ZM",
        "ZW"
      ],
      "external_urls": {
        "spotify": "https://open.spotify.com/album/1x55Z0fYARLdeJVjG2UESs"
      },
      "href": "https://api.spotify.com/v1/albums/1x55Z0fYARLdeJVjG2UESs",
      "id": "1x55Z0fYARLdeJVjG2UESs",
      "images": [
        {
          "height": 640,
          "url": "https://i.scdn.co/image/ab67616d0000b273b20fdc3ee4c262693cfdf005",
          "width": 640
        },
        {
          "height": 300,
          "url": "https://i.scdn.co/image/ab67616d00001e02b20fdc3ee4c262693cfdf005",
          "width": 300
        },
        {
          "height": 64,
          "url": "https://i.scdn.co/image/ab67616d00004851b20fdc3ee4c262693cfdf005",
          "width": 64
        }
      ],
      "name": "Up 2 Më",
      "release_date": "2021-09-10",
      "release_date_precision": "day",
      "total_tracks": 22,
      "type": "album",
      "uri": "spotify:album:1x55Z0fYARLdeJVjG2UESs"
    }
  ]
}
phast
  • 188
  • 1
  • 2
  • 12
  • 2
    Paste the JSON into [app.quicktype.io](https://app.quicktype.io) and check out the models it generates. No, you don't have to include every key if you don't need them. – jnpdx Jan 31 '22 at 21:16
  • @jnpdx HOLY! This is insane. Thank you! – phast Jan 31 '22 at 21:21

1 Answers1

0

Good rule of thumb is, that you need a separate Decodable object for every JSON object (marked with {}) when working with such API.

You can nest Decodable structs. Just don't forget that here, ExternalUrl has to be Decodable too, otherwise you will get an error

struct SpotifyItem: Decodable {
    // ...
    let artists: [Artist]
    let images: [SpotifyImage]
    // ...
}

struct Artist: Decodable {
    let external_urls: ExternalUrl
    let href: String
    let id: String
    // ...
}

struct ExternalUrl: Decodable {
    let spotify: String
}

struct SpotifyImage: Decodable {
    let url: String
    let height: Int
    let width: Int
}

Side Note Answer: I would advise you to do so. It seems like there are ways to decode JSON elements into swift dictionary, but it goes against the type safety that you are trying to achieve. You are parsing JSON into Decodable structs precisely because you want to know ahead of time what are you dealing with.

Don't forget you can still do optional attributes, for example you could have

struct ExternalUrl: Decodable {
    let spotify: String
    let instagram: String?
}

In that case, if instagram is not present, it will be set to nil. My advice would be follow this more modern and safe way of doing things. You can of course parse the entire JSON into a huge [String: Any] object, but you will have to write out everything you want to access anyway. Plus there will be a LOT of type casting and checks, which Codable does for you.

DeepBlue
  • 591
  • 9
  • 18