はじめに
[備忘録] AWS CDKでRDS,RDS Proxy,Lambda を構築 までで、AWS CDKの始め方、lambda, apigateway, RDS の設定と使い方を学んできた。
次にこれらを使って独自のwebサービスを開発したい!
そこで、lambda から spotify api を呼んでプレイリストを作成してみることにした。
実施したこと
- spotify の設定(app の作成および Client ID / Client secret の取得)
- リフレッシュトークンの取得
- アクセストークンの取得
- プレイリスト の作成
1. spotifyの設定
spotify のアカウントは既に持っていたので、そのアカウントでログインした状態で dashboard にアクセス、有効化した。
すると下記画面に遷移するので、 create app からアプリを作成していく。
app の作成完了。
Settings に移動すると、Client ID と Client secret を確認できたのでひかえておく。
2. リフレッシュトークンの取得
spotify api を呼ぶためにはアクセストークンが必要だが、60分の有効期限があるため、リフレッシュトークンからアクセストークンを取得してapiを呼ぶようにする。
リフレッシュトークンを取得するために先に認可コードが必要になる。
下記をブラウザで実行すると、リダイレクト先でURLからcodeを取得できる。
https://accounts.spotify.com/authorize?client_id=${client_id}&response_type=code&redirect_uri=${redirect_uri}&scope=playlist-modify-private%&state=state
ただし、scope は利用する api によって異なる。今回はプレイリストの作成をしたいので、playlist-modify-private とした。
次に、https://accounts.spotify.com/api/token
にPOSTリクエストを送信する。
ここで、ヘッダーには、
- Content-type
- application/x-www-form-urlencoded
- Authorization
- Basic
${client_id}:${client_secret}
をbase64変換したもの
- Basic
リクエストボディには、
- redirect_uri
-
- spotifyの設定で指定したもの
-
- grant_type
- authorization_code
- code
- 先ほど取得したもの
を指定する。
レスポンスボディに resfresh_token が含まれているので、それをこの先利用する。
3. アクセストークンの作成
下記でAPIを呼ぶために必要なアクセストークンを取得する。
const requestBody = JSON.parse(event.body);
const authorizationCode = requestBody.code;
// encode
const client_id = '*****'
const client_secret = '*****'
const client = Buffer.from(`${client_id}:${client_secret}`).toString('base64');
// get access token
const requestBodyForAccessToken = new URLSearchParams();
requestBodyForAccessToken.append('grant_type', 'refresh_token');
if(secureParam['refresh-token']) {
requestBodyForAccessToken.append('refresh_token', *****);
}
const responstForAccessToken = await axios.post('https://accounts.spotify.com/api/token', requestBodyForAccessToken, { headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${client}`
}});
const accessToken = responstForAccessToken.data.access_token;
4. プレイリストの作成
ここから本題の spotify api を呼んでみたいと思う。
プレイリスト名とそのプレイリストに追加する曲名、アーティスト名は、lambdaのリクエストボディから取得する。
export const handler = async (
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
const RESPONSE_HEADERS = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type,Authorization,access-token",
};
const response = {
statusCode: 200,
headers: RESPONSE_HEADERS,
body: JSON.stringify({
message: 'SUCCESS'
})
};
var tracks: any[] = [];
if(event.body){
const requestBody = JSON.parse(event.body);
tracks = requestBody.tracks;
playlistName = requestBody.playlistName;
} else {
response.statusCode = 400;
response.body = JSON.stringify({
message: 'INVALID REQUEST'
});
return response;
}
try{
// search for item
const trackIds: string[] = [];
for await (const [index, track] of tracks.entries()) {
// create url
const searchItemUrl = encodeURI(`${spotifyBaseUrl}/search?q=remaster%20track:${track.song}%20artist:${track.artistName}&type=track`);
const item = await axios.get(searchItemUrl, { headers: {
'Authorization': `Bearer ${accessToken}`
}});
var skip: boolean = false;
item.data.tracks.items.forEach((item: any) => {
if(!skip){
if(item.name.includes(track.song)) {
trackIds.push(item.id);
skip = true;
}
}
})
}
if(trackIds.length === 0) {
response.statusCode = 403;
response.body = JSON.stringify({
message: 'NOT FOUND'
});
return response;
}
// create playlist
const playlistData = {
"name": playlistName,
"public": false,
};
const playlist = await axios.post(`${spotifyBaseUrl}/users/${userId}/playlists`, playlistData, { headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
}});
const playlistId = playlist.data.id;
// add items to playlist
const uris: string[] = [];
trackIds.forEach((track) => {
uris.push(`spotify:track:${track}`);
});
await axios.post(`${spotifyBaseUrl}/playlists/${playlistId}/tracks`, { uris }, { headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
}});
} catch(error) {
console.log(error);
response.statusCode = 500;
response.body = JSON.stringify({
message: 'INTERVAL SERVER ERROR'
});
return response;
}
return response;
};
最後に
参考にした文献を記す。