How to get the album info for a song fetched by MusicDataRequest?

I'm slowly learning the new MusicKit beta for swift.

I've learned to successfully retrieve tracks of type Song using MusicDataRequest, using the following:

...
let countryCode = try await MusicDataRequest.currentCountryCode
if let url = URL(string: "https://api.music.apple.com/v1/catalog/\(countryCode)/songs?filter[isrc]=\(isrc)") {
  let dataRequest = MusicDataRequest(urlRequest: URLRequest(url: url))
  let dataResponse = try await dataRequest.response()
...

However, when I decode the data, there does not seem to be any album information that I can see.

I've tried adding includes=albums to the URL, but I don't think that's the right approach, because when I veiw the Song struct in MusicKit, I don't see a reference to an Album type anywhere.

Any advice on how to retrieve the album information would be most appreciated.

Thanks.

Accepted Answer

Hello @Kimfucious,

Thanks for your question on how to access the albums relationship from a Song.

I'm afraid you've chosen to use the wrong tool for the job here.

When using MusicKit for Swift, you should always try to use other more strongly-typed mechanisms first, such as MusicCatalogSearchRequest or MusicCatalogResourceRequest.

Indeed, to the extent possible, we want to leverage the power of the Swift compiler and of Xcode's auto-completion support to enhance the developer experience, precisely to avoid the sort of confusion you're facing with having to construct a URL whose format the Swift compiler cannot understand.

For this specific purpose, you can find this Song much more easily, without having to construct any URL nor decode the raw data response with any Decodable conforming structure by using MusicCatalogResourceRequest's filtering API:

For example, you can find a song whose isrc property matches a certain value with these few lines of code:

let songsRequest = MusicCatalogResourceRequest<Song>(matching: \.isrc, equalTo: "GBDUW0000059")
let songsResponse = try await songsRequest.response()
if let song = songsResponse.items.first {
    print("Found \(song).")
}

This code produces the following output:

Found Song(id: "697195787", title: "Harder Better Faster Stronger", artistName: "Daft Punk").

Then, you can use the with(…) method to load a more complete representation of this song that includes the albums relationship:

let detailedSong = try await song.with([.albums])
if let album = detailedSong.albums?.first {
    print("\(song) is included\n  in \(album)")
}

which produces the following output:

Song(id: "697195787", title: "Harder Better Faster Stronger", artistName: "Daft Punk") is included
  in Album(id: "697194953", title: "Discovery", artistName: "Daft Punk")

However, with our latest beta 4, you can even achieve the same result with fewer lines of code, and also more efficiently, by including .albums in MusicCatalogResourceRequest's properties:

var songsRequest = MusicCatalogResourceRequest<Song>(matching: \.isrc, equalTo: "GBDUW0000059")
songsRequest.properties = [.albums]

let songsResponse = try await songsRequest.response()
if let song = songsResponse.items.first, let album = song.albums?.first {
    print("\(song) is included\n  in \(album)")
}

which also produces the same output as above:

Song(id: "697195787", title: "Harder Better Faster Stronger", artistName: "Daft Punk") is included
  in Album(id: "697194953", title: "Discovery", artistName: "Daft Punk")

Back to my initial comment, MusicDataRequest is a very powerful tool, but one that is designed to be used only as a last resort, when you can't get access to the data you need with other APIs such as the ones I just went over. For example, MusicDataRequest is the right tool for the job if you're trying to load content from Apple Music API which isn't modeled in MusicKit for Swift, such as catalog charts.

I hope this helps.

Best regards,

This is excellent info, @JoeKun. Thank you very much for being so super helpful! I gonna need to add you as a co-author for my app 😊

You know, I looked at MusicCatalogResourceRequest before, but the docs confused me. As I am used to working with the Apple Music API, MusicDataRequest seemed more familiar. Thanks for setting me straight.

I'm not sure if this will ever happen, but if the docs had examples like yours in them, they'd be a lot easier to connect the dots.

Hi @Kimfucious,

Indeed, I agree with you that we could use some more documentation with specific examples. We sort of had to focus most of our efforts on the core mechanics of the framework in preparation of the first official version of iOS 15.

Meanwhile, we’re trying to make up for it by being pretty responsive and thorough in the forums.

But I’m hoping we can improve the developer documentation along those lines in the future.

Thanks for the feedback!

Best regards,

@JoeKun is there anyway to leverage MusicCatalogSearchRequest to get a response with top results similar to what we would get in the response from "https://api.music.apple.com/v1/catalog/%5C(countryCode)/search?term=something&with=topResults"

Hello @harryklein9,

Top results are not exposed in the response for MusicCatalogSearchRequest at this time.

Could you file a ticket on Feedback Assistant for us to consider that as an enhancement for MusicKit?

Thanks,

Hello @harryklein9,

We have introduced a new property for MusicCatalogSearchRequest in iOS 16 beta 1 for fetching top results from Apple Music API: includeTopResults.

It's now easier than ever to load catalog search top results with MusicKit.

I hope this helps.

Best regards,

@JoeKun

How do we use the includeTopResults param over the REST interface?

How to get the album info for a song fetched by MusicDataRequest?
 
 
Q