Vue.jsで遊んでみた　【STEP 2】axios の導入

前回記事
[Vue.jsで遊んでみた　【STEP 1】Vue.js の導入](https://qiita.com/koujin/items/34bbfbf928d2c93a70e4)

## 今回の内容
Vue.jsの勉強第二回はaxiosを用いてAPIをたたいてみたいと思います。expressでAPIも自作できるのでそちらの実装も行いたいと思います。

#### 参考
[Vue.jsとAxiosなら驚くほど簡単に作れる！外部APIを使ったWebアプリの実例](https://www.webprofessional.jp/fetching-data-third-party-api-vue-axios/)
[axios を利用した API の使用](https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html)
[axiosのパラメータ指定方法まとめ](https://qiita.com/taroc/items/f22f7dd5d6d5443c72a4)
[express のリファレンス](https://expressjs.com/ja/4x/api.html#express)
[Expressを用いた簡単なAPIの作り方　まとめ](https://qiita.com/yujiro0102/items/a973a0ae05a794d24eb5)

## 導入
### axios
そもそもaxiosとは何なのか。参考にも上げたVue.jsのリファレンスから引用します

> ウェブアプリケーションを構築するとき、 API からデータを取得して表示することがよくあります。これを行うにはいくつかの方法があり、一般的なアプローチは Promise ベースの HTTP クライアントの axios を使うことです。

要するに公式のお墨付きのVue.jsと相性の良いHTTPクライアントのフレームワークというところですかね。お墨付きならあえて他の方法を使う必要性もないかと思いますのでこちらを用いてAPIをでデータを取得します。
こちらも導入方法は簡単で、以下の一行をhtmlファイルに導入するだけです。便利。

~~~html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
~~~

### APIを自作する
次にAPIを自作したいと思います。現在使っているNode.jsのライブラリのExpressはAPIを作るのも非常に簡単です。
今回は`/timer`へのGETリクエストに対して、クエリに与えられた秒数だけ返答を待機するAPIを`index.js`に追加します。

~~~js
app.get("/timer",(req,res)=>{
  let time = req.query.time
  console.log(req.query)
  if(!time) time = 0
  setTimeout(()=>{res.json({getTimer : time})},time*1000)
})
~~~

`app.get`を`app.post`に変更すればpostリクエストに対応します。GETリクエストのクエリパラメータは`req.query`から取得できます。
返答は`res.json`でオブジェクトをjson形式にして送ってもらいました。
`res.send(JSON.stringify({getTimer : time}))`のように書いても同様の動き方になります。返答の形式はexpressの公式にいろいろ上がってるのでそちらで確認してみてください。

## APIからデータを取ってくる
前回のレイアウトの一部を改良して、処理したAPIに設定した時間を結果が返ってきた順に並べて表示するViewを作りました。

~~~html:index.html
<html>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <body>
        <div id="app">
            <h3>complete task</h3>
            <ol>
                <li v-for="task in completeTask">
                    {{task}}
                </li>
            </ol>
            <button v-on:click="dealTask(1)">1</button>
            <button v-on:click="dealTask(2)">2</button>
            <button v-on:click="dealTask(3)">3</button>
        </div>
    </body>
    <script src="js/vue.js"></script>
</html>
~~~

~~~js:vue.js
var app = new Vue({
  el: '#app',
  data: {
    completeTask: []
  },
  methods : {
    dealTask :async function(time){
      await axios.get("http://localhost:3000/timer",{
        params:{
          time : time
        }
      }).then(res =>{
        console.log(res.data)
        app.completeTask.push(`done ${res.data.getTimer}`)
      }).catch(err=>{
        console.log(err)
        app.completeTask.push("miss ${res.data.getTimer}")
      })
    }
  }
})
~~~

axiosはPromise関数なので`then/catch`等で取得したデータに対する処理を書いております。今後を見越して`async/await`を記述してますが、今回特に意味はなしてないです。

### 実際に動かしてみて得た気づき
実際に動かしてみてポチポチボタンを押してみたところ、各ボタンは非同期に動いてくれますが、同一のボタンは順番で動いていることが、サーバーとブラウザのコンソールから確認できました。(3->3->2->2->1->1)の順で連続してボタンを押下すると以下のようなログがサーバー側で吐き出されたことから確認できます。

~~~
{ time: '3' }
{ time: '2' }
{ time: '1' }
{ time: '1' }
{ time: '2' }
{ time: '3' }
~~~

`await`外しても同様の結果でした。そこで以下のように`index.html`を書き換えてみました

~~~html:index.html
<button v-on:click="dealTask(1)">1</button>
<button v-on:click="dealTask(3)">2</button>
<button v-on:click="dealTask(3)">3</button>
~~~

この状態でボタンを同じ順番で連続して押下すると、サーバー側のログは以下のようになりました

~~~
{ time: '3' }
{ time: '1' }
{ time: '1' }
{ time: '3' }
{ time: '3' }
{ time: '3' }
~~~

これから考えるに、同じ関数の同じ引数の処理は一つの処理が終わらないと次の処理が走らない仕様になってるようです。おそらくVue.jsの仕様なんじゃないかと思いますが、詳しい方は教えてください。

## まとめ
　この時差式APIは非同期処理やるうえで結構学びがあると思うので他にもいろいろポチポチしたり設定変えたりして楽しく学んでいただきたいです。