Book

Exploring MusicKit and Apple Music API

Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!

Are you a fan of the “Blend” feature on Spotify and wish you could create the same experience for Apple Music users? I am working on a new app Fussion, that will be designed to recreate the Spotify Blend experience for Apple Music enthusiasts.

The core part of the app focuses on the user’s personal Apple Music station, and this tutorial will guide you through the process of fetching it using MusicKit and the Apple Music API.

Fetching User’s Personal Apple Music Station

Working with the personal station is straightforward. Apple Music API has a dedicated endpoint, and we can use MusicKit to parse the station data.

Endpoint Overview

To fetch the current user’s personal Apple Music station, we use the following endpoint:

https://api.music.apple.com/v1/catalog/{storefront}/stations?filter[identity]=personal

This endpoint returns an array of stations from which we can extract the desired station data.

Decoding the Response

The station response will look like the following JSON structure:

{
    "data": [
        {
            "id": "ra.u-04bcab05bb818ecf1abb70ff757",
            "type": "stations",
            "href": "/v1/catalog/in/stations/ra.u-04bcab05bb818ecf1abb70ff757",
            "attributes": {
                "isLive": false,
                "name": "Rudrank Riyam’s Station",
                "mediaKind": "audio",
                "artwork": {
                    "width": 2400,
                    "height": 2400,
                    "url": "https://is1-ssl.mzstatic.com/image/thumb/Features124/v4/7b/1d/f0/7b1df048-0017-8ac0-98c9-735f14849606/mza_7507996640781423701.png/{w}x{h}bb.jpg"
                },
                "url": "https://music.apple.com/in/station/rudrank-riyams-station/ra.u-04bcab05bb818ecf1abb70ff757",
                "playParams": {
                    "id": "ra.u-04bcab05bb818ecf1abb70ff757",
                    "kind": "radioStation",
                    "format": "tracks",
                    "stationHash": "CgoIByIGCIDRuo8f",
                    "hasDrm": false,
                    "mediaType": 0
                }
            }
        }
    ],
    "meta": {
        "filters": {
            "identity": {
                "personal": [
                    {
                        "id": "ra.u-04bcab05bb818ecf1abb70ff757",
                        "type": "stations",
                        "href": "/v1/catalog/in/stations/ra.u-04bcab05bb818ecf1abb70ff757"
                    }
                ]
            }
        }
    }
}

We can see that the data contains an array of Station objects. To decode this response in your Swift project with MusicKit, we use the MusicDataRequest to decode it into a MusicItemCollection<Station> structure.

Handling Errors

It’s essential to handle potential errors effectively. We define an enum for potential errors you might encounter while fetching the personal music station:

enum PersonalStationError: Error {
  case invalidURL
  case notFound
}

This enum includes two cases: invalidURL and notFound, representing possible issues that might arise while fetching the personal music station.

Building the Request

Next, we fetch the current country code which we use as a storefront:

let storefront = try await MusicDataRequest.currentCountryCode

After fetching the current country code (used as a storefront), we build the URL request using URLComponents and include a query item to filter the personal station:

var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "api.music.apple.com"
urlComponents.path = "/v1/catalog/\(storefront)/stations/personal"
urlComponents.queryItems = [URLQueryItem(name: "filter[identity]", value: "personal")]

Making the Request

We use the MusicDataRequest to handle both the authorisation and music user token:

guard let url = urlComponents.url else {
  throw PersonalStationError.invalidURL
}

let request = MusicDataRequest(urlRequest: URLRequest(url: url))
let response = try await request.response()

After receiving the response, we decode the data into a collection of MusicKit’s Station:

let stations = try JSONDecoder().decode(MusicItemCollection<Station>.self, from: response.data)

Finally, extract the first station from the list:

guard let personalStation = stations.first else {
  throw PersonalStationError.notFound
}

debugPrint(personalStation)

That’s it! This fetches your personal Apple Music station using MusicKit. Printing the station to the console, we get the following for my station:

Station(
  id: "ra.u-04bcab05bb818ecf1abb70ff757",
  name: "Rudrank Riyam’s Station",
  isLive: false,
  url: "https://music.apple.com/in/station/rudrank-riyams-station/ra.u-04bcab05bb818ecf1abb70ff757"

Playing the Station

To play the fetched station, we set the queue of the player and play it:

do {
  guard let station = station else { return }
  ApplicationMusicPlayer.shared.queue = [station]
  try await ApplicationMusicPlayer.shared.play()
} catch {
  debugPrint(error)
}

Conclusion

Fetching a user’s personal Apple Music station using MusicKit is simple. However, it’s crucial to handle potential errors appropriately and provide clear feedback to your users. With Fussion, I am hoping to create a similar blend-like experience for Apple Music users.

Happy coding, and keep the station playing!

Book

Exploring MusicKit and Apple Music API

Unlock the full power of MusicKit & Apple Music APIs in your apps with the best guide! Use code musickit-blog for a limited-time 35% discount!

Written by

Rudrank Riyam

Hi, my name is Rudrank. I create apps for Apple Platforms while listening to music all day and night. Author of "Exploring MusicKit". Apple WWDC 2019 scholarship winner.