Vue.jsでSpotify APIを叩いてなうぷれを取得してみよう

# 概要
この記事はVue.jsでSpotify APIを叩いてみようという記事です。
Spotifyで再生中の曲情報を取得し、ブラウザの画面に表示するのがゴールです。

![nowplaying.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/64fb0eb8-666b-dbd4-3514-670224c79c10.png)

# Vue.jsの環境構築
JavaScriptフレームワークのVue.jsを使います。

まずVue.jsの環境を準備します。
手元で環境構築するのが面倒だと思う人は、ちょっと触ってみる程度なら[CodeSandbox](https://codesandbox.io/)等オンラインエディタを利用してもいいかもしれません。

## 前提環境
Node.jsがインストールされている前提です。まだインストールしていない場合は、インストールしてください。

- Node.js 12.16.1
- npm 6.9.0

## インストールと起動

Vue CLIをインストールします。

```bash
npm install -g @vue/cli
```

プロジェクトを始めるディレクトリに移動した後、Vueプロジェクトを生成します。

```bash
vue create my-project
```

いろいろ聞かれます。

```bash
? Please pick a preset: default (babel, eslint)
? Pick the package manager to use when installing dependencies: NPM
```

開発サーバを起動してみます。

```bash
$ npm install
$ npm run serve
```

デフォルトでは8080番ポートで起動します。
https://localhost:8080
アクセスして、Vue.jsの初期ページが表示されたら準備完了です。

![welcomevue.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/8f5a74d1-186e-08c5-adaf-747af0e8e538.png)


# Spotify APIの準備

Spotify Web APIを使う準備をします。

やること

- APIキーの取得
- 叩いてみる(Postmanとかで)

## APIキーの取得

Spotify APIを使うアプリケーションを作るには、Client IDを取得する必要があります。

https://developer.spotify.com/dashboard/applications

「CREATE CLIENT ID」から作りましょう。
作り終えるとClient IDとClient Secretが確認できます。APIを叩くときの認証に必要です。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/e40555ac-4c23-1375-225d-8ce5df438aad.png)

また、認証後にリダイレクトするURIを事前に許可しておく必要があります。
ここで設定したURI以外にはリダイレクトできません。
「EDIT SETTING」から設定します。今回は、```http://localhost:8080```を許可しておきます。

![redirecturis.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/90199185-2fe6-b8c0-008b-404baa57a77c.png)


## APIにアクセス

### アクセストークンの取得

Spotify APIを叩く前に、認証APIを使ってアクセストークンを取得する必要があります。

詳しいことは[公式のドキュメント](https://developer.spotify.com/documentation/general/guides/authorization-guide/)に載っています。ここでは今回使うものだけ説明します。

GETメソッドで、エンドポイントは
```https://accounts.spotify.com/authorize```
です。
クエリパラメータは次の3つ

- response_type=token
- client_id=(生成したClient ID)
- redirect_uri=http://localhost:8080

繋げると次のようになります。

```
https://accounts.spotify.com/authorize?response_type=code&client_id=hogehogehogehogehoge&redirect_uri=http://localhost:8080
```

これをブラウザからアクセスすると、Spotifyの認証画面が出ます。

![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/b5bd89d6-79fc-9e0c-25fd-6f126632c69a.png)

Spotifyアカウントでログインして連携許可すると、リダイレクトURIである```localhost:8080```に遷移します。
このとき、アクセストークンがURIに含まれています。
```http://localhost:8080/#access_token=(アクセストークン)&token_type=Bearer&expires_in=3600```

### 再生中の曲情報取得

再生中の曲情報を取得するAPI「Get the User's Currently Playing Track」を叩いてみます。
エンドポイントは```https://api.spotify.com/v1/me/player/currently-playing```です。
リクエストのヘッダに、さっき取得したアクセストークンをつけます。
Postmanだとこんな感じ。
![postman.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/d12b7bef-71cf-0579-ac9b-af6f41fdabb4.png)

リクエストを送ると、再生中の曲情報のJSONデータが返ってくるのが確認できます。

![postman2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/aa25be5b-c2f2-00a1-df78-b517db5c9cc7.png)

# Vue.js, Axiosで実装
今回使うライブラリ

- Vue Router

Vue RouterはVue.jsのエコシステムのひとつで、パスをコンポーネントにルーティングしてくれるモノです。今回は認証後のリダイレクトをさばくために使います。

- Axios

AxiosはHTTPクライアントです。最近のJavaScriptでよく使われます。非同期処理・Promiseを使ってAPIとやりとりできます。
npmでインストールします。

```bash
$ npm install vue-router
$ npm install axios
```

Vue Routerを使うためのファイルを作成します。

```bash
$ mkdir src/router
$ touch src/router/index.js
```

とりあえず必要なものだけ。ルーティングの記述はもう少し後でします。

```javascript:src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = []

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router
```

```main.js``` に次のように記述します。

```javascript:src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')
```

なうぷれページ用のディレクトリとファイルを作成します。

```bash
mkdir src/views
touch src/views/NowPlaying.vue
```
とりあえずこれだけ

```vue:src/views/NowPlaying.vue
<template>
  <div class="nowplaying">
    <h1>NowPlaying</h1>
  </div>
</template>

<script>
export default {

}
</script>
```

Vue Routerを使うための記述をします。
```App.vue``` はこれだけにします。

```vue:src/App.vue
<template>
  <div id="app">
    <router-view />
  </div>
</template>
```

### Vue Router

Vue Routerのファイルにルーティングするためのコードを記述します。

```javascript:src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import NowPlaying from '@/views/NowPlaying.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'NowPlaying',
    component: NowPlaying
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router
```

ここまでの状態で ```npm run serve``` すると、作成したページが表示されることが確認できます。

![routing.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/2e81f43b-2c37-98d4-94d2-635d09c57f8d.png)

## 認証部分での問題点と解決策

認証部分を作ります。
「認証」ボタンはクリックしたら認証URLに飛ぶボタンです。

リダイレクトしてきたURLからパラメータを取得しますが、ここで問題が起きます。
リダイレクト後のURLが
```http://localhost:8080/#access_token=hogehoge...&token_type=Bearer&...```
なため、Vue Routerの```$route.query```でパラメータを取得できません。
```$route.hash```でならパラメータが取れますが、オブジェクトではなく全部繋がった文字列となってしまい都合が悪いです。
```http://localhost:8080/?access_token=hogehoge...&token_type=Bearer&...```
なら都合が良いので、ここでは```$route.hash```が空でない場合に「#」を「?」に置換して同ページにリダイレクトさせることで解決します。

### Vue Router

```javascript:src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import NowPlaying from '@/views/NowPlaying.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'NowPlaying',
    component: NowPlaying,
    props: (route) => {
      return { routeParams: route.query }
    }
  }
]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router
```
### NowPlaying.vue

```vue:src/views/NowPlaying.vue
<template>
  <div class="nowplaying">
    <h1>NowPlaying</h1>
    <button @click="spotifyLogin">認証</button>
    <p>{{ routeParams }}</p>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      nowPlaying: null
    }
  },
  props: {
    routeParams: Object
  },
  created: function() {
    if (this.$route.hash) {
      this.$router.push(this.$route.fullPath.replace('#', '?'))
    }
  },
  methods: {
    spotifyLogin: function() {
      let endpoint = 'https://accounts.spotify.com/authorize'
      let response_type = 'token'
      let client_id = 'ここにSpotify Developersで取ったクライアントIDを入れます'
      let redirect_uri = 'http://localhost:8080'
      let scope = 'user-read-currently-playing'
      location.href = endpoint + 
        '?response_type=' + response_type +
        '&client_id=' + client_id +
        '&redirect_uri=' + redirect_uri +
        '&scope=' + scope
    }
  }
}
</script>
```

認証ボタンを押して、アクセストークンが取れることを確認します。

![auth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/cab50c1a-b70c-ec11-9044-8ccf906bc03f.png)

## なうぷれ取得と表示

あとは、再生中曲情報取得APIを叩いて、レスポンスデータを表示すればゴールです。
「再生中の曲情報取得」ボタンのクリックでAxiosがGETし、レスポンスをVueのデータに突っ込んでいます。

### NowPlaying.vue

```vue:src/views/NowPlaying.vue
<template>
  <div class="nowplaying">
    <h1>NowPlaying</h1>
    <button @click="spotifyLogin">認証</button>
    <br>
    <button @click="getNowPlaying">再生中の曲情報取得</button>
    <div v-if="nowPlaying != null">
      <p>今再生中の曲 : {{ nowPlaying.item.artists[0].name }} の {{ nowPlaying.item.name }}</p>
      <img :src="nowPlaying.item.album.images[1].url">
    </div>
  </div>
</template>

<script>
import axios from 'axios'
export default {
  data: function() {
    return {
      nowPlaying: null
    }
  },
  props: {
    routeParams: Object
  },
  created: function() {
    if (this.$route.hash) {
      this.$router.push(this.$route.fullPath.replace('#', '?'))
    }
  },
  methods: {
    spotifyLogin: function() {
      let endpoint = 'https://accounts.spotify.com/authorize'
      let response_type = 'token'
      let client_id = 'ほげほげ'
      let redirect_uri = 'http://localhost:8080'
      let scope = 'user-read-currently-playing'
      location.href = endpoint + 
        '?response_type=' + response_type +
        '&client_id=' + client_id +
        '&redirect_uri=' + redirect_uri +
        '&scope=' + scope
    },
    getNowPlaying: function() {
      let endpoint = 'https://api.spotify.com/v1/me/player/currently-playing?market=JP'
      let data = {
        headers: {
          'Authorization': this.routeParams.token_type + ' ' + this.routeParams.access_token
        },
        data: {}
      }
      axios
      .get(endpoint, data)
      .then(res => {
        this.nowPlaying = res.data
      })
      .catch(err => {
        console.error(err)
      })
    }
  }
}
</script>
```

ブラウザで確認。

![nowplaying.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262502/64fb0eb8-666b-dbd4-3514-670224c79c10.png)

できましたね！

# おわりに

Vue.jsで、SpotifyのAPIを叩いてデータを表示できました。今回はなうぷれ取得だけでしたが、これをベースに、もっとSpotifyとなんやかんやするWebアプリが作れそうですね。
以上で終わります。

# 参考
- [Spotify Authorization Guide](https://developer.spotify.com/documentation/general/guides/authorization-guide/)
- [Spotify Web API Reference - Get the User's Currently Playing Track](https://developer.spotify.com/documentation/web-api/reference-beta/#endpoint-get-the-users-currently-playing-track)
- [Vue Router API Reference - The Route Object](https://router.vuejs.org/api/#the-route-object)