LoginSignup
0
0

[備忘録] lambda(Node.js) から spotify api を呼んでみた

Last updated at Posted at 2023-10-29

はじめに

[備忘録] AWS CDKでRDS,RDS Proxy,Lambda を構築 までで、AWS CDKの始め方、lambda, apigateway, RDS の設定と使い方を学んできた。
次にこれらを使って独自のwebサービスを開発したい!
そこで、lambda から spotify api を呼んでプレイリストを作成してみることにした。

実施したこと

  1. spotify の設定(app の作成および Client ID / Client secret の取得)
  2. リフレッシュトークンの取得
  3. アクセストークンの取得
  4. プレイリスト の作成

1. spotifyの設定

spotify のアカウントは既に持っていたので、そのアカウントでログインした状態で dashboard にアクセス、有効化した。
すると下記画面に遷移するので、 create app からアプリを作成していく。
image.png
image.png
app の作成完了。
image.png
Settings に移動すると、Client ID と Client secret を確認できたのでひかえておく。
image.png

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変換したもの

リクエストボディには、

  • redirect_uri
      1. spotifyの設定で指定したもの
  • grant_type
    • authorization_code
  • code
    • 先ほど取得したもの

を指定する。
レスポンスボディに resfresh_token が含まれているので、それをこの先利用する。

3. アクセストークンの作成

下記でAPIを呼ぶために必要なアクセストークンを取得する。

app-lambda.ts
    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のリクエストボディから取得する。

app-lambda.ts
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;
};
    

最後に

参考にした文献を記す。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0