Fetching Catalog Top Charts Genres

Hi there!

I am working on the genres screen and realised that I can directly use MusicCatalogResourceRequest for fetching genre with a particular ID:

func getGenres() async {
    do {
      let genreID = MusicItemID("17")
      let request = MusicCatalogResourceRequest<Genre>(matching: \.id, equalTo: genreID)
      let genreResponse = try await request.response()
      print(genreResponse.items)
    } catch {
      print(error)
    }
  }

Apple Music also has an API to get the top charts genres. How would I do it without using MusicDataRequest, or is it the only way?

My current approach:

typealias Genres = MusicItemCollection<Genre>

do {
    let countryCode = try await MusicDataRequest.currentCountryCode
    let genreURL = "https://api.music.apple.com/v1/catalog/\(countryCode)/genres"
    
    guard let url = URL(string: genreURL) else {
        throw URLError(.badURL)
    }
    
    let request = MusicDataRequest(urlRequest: URLRequest(url: url))
    let response = try await request.response()
    
    let genre = try JSONDecoder().decode(Genres.self, from: response.data)
    print(genre)
    
} catch {
    print(error)
}

Thank you!

Accepted Reply

Hello @snuff4,

If you want to get all catalog genres from the endpoint described here, you do need to use MusicDataRequest, much like you're doing here.

In fact, this is the exact example we used in our WWDC session Meet MusicKit for Swift to show how to load data from an arbitrary Apple Music API endpoint using MusicDataRequest.

The only thing I would suggest you could do even better than what we showed in the WWDC session is to leverage the fact that this endpoint returns a simple resource collection, which corresponds to MusicItemCollection in MusicKit.

Hence, you can simplify your code further in this case so you don't even have to define your own Decodable conforming Genres structure; instead, you can just do this:

    let decoder = JSONDecoder()
    let genres = try decoder.decode(MusicItemCollection<Genre>.self, from: response.data)
    print(genres)

Using MusicItemCollection in this way is also recommended when decoding data loaded using MusicDataRequest from an Apple Music API endpoint that returns a paginated resource collection, and that's where the we see the full power of MusicItemCollection; indeed, once you get this initial instance of MusicItemCollection, you can easily use the hasNextBatch property to check if there is more data to be loaded, and the nextBatch(…) method to load the next batch in a single line of code.

I hope this helps.

Best regards,

Replies

Hello @snuff4,

If you want to get all catalog genres from the endpoint described here, you do need to use MusicDataRequest, much like you're doing here.

In fact, this is the exact example we used in our WWDC session Meet MusicKit for Swift to show how to load data from an arbitrary Apple Music API endpoint using MusicDataRequest.

The only thing I would suggest you could do even better than what we showed in the WWDC session is to leverage the fact that this endpoint returns a simple resource collection, which corresponds to MusicItemCollection in MusicKit.

Hence, you can simplify your code further in this case so you don't even have to define your own Decodable conforming Genres structure; instead, you can just do this:

    let decoder = JSONDecoder()
    let genres = try decoder.decode(MusicItemCollection<Genre>.self, from: response.data)
    print(genres)

Using MusicItemCollection in this way is also recommended when decoding data loaded using MusicDataRequest from an Apple Music API endpoint that returns a paginated resource collection, and that's where the we see the full power of MusicItemCollection; indeed, once you get this initial instance of MusicItemCollection, you can easily use the hasNextBatch property to check if there is more data to be loaded, and the nextBatch(…) method to load the next batch in a single line of code.

I hope this helps.

Best regards,

Oh yes, if you see my code example, Genres is a typealias for MusicItemCollection<Genre>! :D

MusicItemCollection is one of the best structures in MusicKit, and it simplifies so many things.

Oops, sorry I missed the typealias! Looks great!!

Hi @snuff4,

Just a quick update to tell you that you no longer need to use MusicDataRequest to get the list of top-level genres from the catalog.

On iOS 16.0 Beta 2, you can now use MusicCatalogResourceRequest:

let genresRequest = MusicCatalogResourceRequest<Genre>()
let genresResponse = try await genresRequest.response()
let genres = genresResponse.items
print(genres)

I hope this helps.

Best regards,