串接多種 API 製作Lady Gaga App(Spotify篇)

1.畫面截圖:

2.App操作GIF:

3.GitHub連結:

4.程式解說:

取得Spotify的OAuth Access Token

如果你是高手高手高高手,可以直接看Spotify的教學文章

不是高手的朋友也別擔心,我已經幫你們讀完了,跟著以下步驟就可以取得Spotify的OAuth Access Token

可謂知己知彼,百戰百勝,我們先看申請OAuth Access Token的指令

curl -H "Authorization: Basic ZjM...zE=" -d grant_type=authorization_code -d code=MQCbtKe...44KN -d redirect_uri=https%3A%2F%2Fwww.foo.com%2Fauth https://accounts.spotify.com/api/token

依序下步驟,滿足上面的指令

第一步:

請先到下方網址登入

建立一個App

基本資料隨便填一填後,就會有以下畫面,記錄好Client ID和Client Secret後

第二步:

請點擊EDIT SETTINGS

Redirect URIs這欄填入隨便一個網址(我是用我的github),並儲存

再把你的網址到以下的網站轉換一下,並且記錄結果

第四步:

還記得Client ID和Client Secret嗎?請用以下格式

你的Client ID:你的Client Secret

再到以下網址轉成 base64,並且記錄結果

第五步:

有了前四步的東西後,請填入以下網址

https://accounts.spotify.com/authorize?client_id=第一步的Client ID&response_type=code&redirect_uri=第二步轉換後的網址&scope=第三步你選的範圍

再把這個網址在新的分頁打開,結果如下:

按下同意後,會回到你之前第二步填的Redirect URIs

但仔細一看,網址後面多了 code=**你要記錄的code*****

p.s. 上圖的code並不是完整的

第六步:

我們蒐集好了申請Token需要的東西,就到終端機輸入指令吧

curl -H "Authorization: Basic 第四步的結果" -d grant_type=authorization_code -d code=第五步的code -d redirect_uri=第二步轉換後的網址 https://accounts.spotify.com/api/token

把紅框這段複製到jsoneditoronline來看

有了Bearer Token,我們可以利用Postman來獲得Json,再利用Postman的幫我們寫的Code串接

p.s. 不知道Postman的朋友,可以去看看我之前寫的Twitter篇

串接Json資料

我的App用到了lady gaga的profile,專輯,熱門歌曲,相關歌手

這些resource url可詳見spotify的網站

我們以熱門歌曲為例,用到以下項目

struct spotifyTrackData: Identifiable {
var id: String
var name: String
var artists: String
var imgurl: String
var external_urls: String
}

雖然Json有preview_url可以試聽30秒,但是Lady Gaga的歌曲在這一欄都是null,我就退而求其次,使用external_urls

接著利用Postman的幫我們寫的Code串接

class getspotifyTrackData: ObservableObject {

@Published var data = [spotifyTrackData]()
init(){
let token = test()
var request = URLRequest(url: URL(string: "https://api.spotify.com/v1/artists/1HY2Jd0NmPuamShAr6KMms/top-tracks?country=TW")!,timeoutInterval: Double.infinity)
request.addValue("Bearer 你的token", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let session = URLSession(configuration: .default)
session.dataTask(with: request){(data, _, err) in
if err != nil{

print((err?.localizedDescription)!)
return
}

let json = try! JSON(data: data!)
let tracks = json["tracks"].array!
for i in tracks{
let id = i["id"].stringValue
let name = i["name"].stringValue
let imgurl = i["album"]["images"][0]["url"].stringValue
let artistArr = i["artists"].array!
var artists = ""
for j in artistArr{
if artists == ""{
artists = j["name"].stringValue
}
else {
artists = artists + "," + j["name"].stringValue
}
}
let external_urls = i["external_urls"]["spotify"].stringValue
DispatchQueue.main.async {
self.data.append(spotifyTrackData(id: id, name: name, artists: artists, imgurl: imgurl, external_urls: external_urls))
}
}
}.resume()


}
}

此時我眉頭一皺,發現事情並不單純

回頭看看Bearer Token,發現使用期限只有3600秒,也就是1小時

token過期可是拿不到資料的,所以需要refresh token幫你拿到新的token

curl -H "Authorization: Basic 第四步的結果" -d grant_type=refresh_token -d refresh_token=你的refresh token https://accounts.spotify.com/api/token

可以用以上指令到終端機獲得新的指令,但每一個小時就要換一次太麻煩了,我們直接把指令寫在App裡,每次開啟就會獲得新的token

至於怎麼寫,又要請Postman幫忙了

Username是Client ID,Password是Client Secret

除了Authorization,Body也要加入項目

按下send後就會有新的token

而Postman寫的Code如下:

import Foundationvar semaphore = DispatchSemaphore (value: 0)let parameters = "grant_type=refresh_token&refresh_token=你的refresh token"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://accounts.spotify.com/api/token")!,timeoutInterval: Double.infinity)
request.addValue("", forHTTPHeaderField: "")
request.addValue("Basic 第四步的結果", forHTTPHeaderField: "Authorization")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue("__Host-device_id=AQBPwRuubEaHLe3qzncUC_qxhNi3w6W_sXdPNQenUVz1lXG86eZs3u2hW3kbO2RZEz7-XaJA9gE6J-ZHFpnGNlfS-n3BCM6aYe4", forHTTPHeaderField: "Cookie")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
semaphore.signal()
}
task.resume()
semaphore.wait()

再結合寫的Code串接熱門歌曲,完整程式碼如下

class getspotifyTrackData: ObservableObject {

@Published var data = [spotifyTrackData]()
init(){
let parameters = "grant_type=refresh_token&refresh_token=你的refresh token"
let postData = parameters.data(using: .utf8)
if let url = URL(string: "https://accounts.spotify.com/api/token"){
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Basic 第四步的結果", forHTTPHeaderField: "Authorization")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.addValue("__Host-device_id=AQBPwRuubEaHLe3qzncUC_qxhNi3w6W_sXdPNQenUVz1lXG86eZs3u2hW3kbO2RZEz7-XaJA9gE6J-ZHFpnGNlfS-n3BCM6aYe4; __Secure-TPASESSION=AQCz/AtmF0i7zemzOI63JpokY8izsrk2ImSVSTMRoV9wFeKzaJ3fo6PpoDMKHrlkARSTo8l56+mTXLbOHybt/hF9KwIxAZ4C11Q=; csrf_token=AQDysFWy0rN9M1GtLlb6eRbkaTuqNeRmyQmw5VIxjzUTAVHxYgmK41DZhtFdkivrgIZcEgbMBqQFFmDlGQ", forHTTPHeaderField: "Cookie")
request.httpBody = postData
URLSession.shared.dataTask(with: request) { (data, response, error) in
let json = try! JSON(data: data!)
let token = json["access_token"].stringValue
var request = URLRequest(url: URL(string: "https://api.spotify.com/v1/artists/1HY2Jd0NmPuamShAr6KMms/top-tracks?country=TW")!,timeoutInterval: Double.infinity)
request.addValue("Bearer " + token, forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let session = URLSession(configuration: .default)
session.dataTask(with: request){(data, _, err) in
if err != nil{

print((err?.localizedDescription)!)
return
}

let json = try! JSON(data: data!)
let tracks = json["tracks"].array!
for i in tracks{
let id = i["id"].stringValue
let name = i["name"].stringValue
let imgurl = i["album"]["images"][0]["url"].stringValue
let artistArr = i["artists"].array!
var artists = ""
for j in artistArr{
if artists == ""{
artists = j["name"].stringValue
}
else {
artists = artists + "," + j["name"].stringValue
}
}
let external_urls = i["external_urls"]["spotify"].stringValue
DispatchQueue.main.async {
self.data.append(spotifyTrackData(id: id, name: name, artists: artists, imgurl: imgurl, external_urls: external_urls))
}
}
}.resume()


}.resume()
}


}
}

至於畫面設計,下載我的app來細細品嚐吧!

5.結語:

spotify應該是這五個api裡,串起來最累的,為了取得token讓我煞費苦心

如果觀眾老爺有看不懂的地方,可以留言告訴我;覺得這篇文章對你有幫助,不妨幫我拍手以及follow我

--

--