Vue:axiosとvue-cliを使ったAPI呼び出し

Vue:axiosとvue-cliを使ったAPI呼び出し

Vueで使える、PromiseベースのHTTPクライアント axios のインストールからAPI呼び出しまでを、vue-cliを使ってやります。



インストール

npm install axios vue-axios


Vue CLIのプロジェクト作成

VueCLIインストール

インストールコマンド

npm install -g @vue/cli

インストール確認

vue --version
@vue/cli 4.5.11


プロジェクト新規作成

vue create testjs

いくつか候補が出てくるが、とりあえず「Default ([Vue 2] babel, eslint)」を選んだ。


ホットリロード環境起動

cd testjs
npm run serve


API呼び出し

Bitcoinの価格を取得するCoinDeskAPIを呼んでみます。


APIの調査

まずエンドポイントのURLと、取得できるデータがどのようなものかを調べます。


coindesk

https://www.coindesk.com/coindesk-api


を読んでいくと、エンドポイントが以下のURLであることが分かりました。

https://api.coindesk.com/v1/bpi/currentprice.json

ひとまずブラウザで開いてみます。


Vueから呼び出し

main.jsを編集します。

  • main.jsでVue.use() グローバルメソッドを呼び出すことで、プラグインが使用できるようになります。必ずnew Vue()の前に呼び出す必要があります。
import Vue from 'vue'
import App from './App.vue'
import axios from  'axios'          //追加
import VueAxios from  'vue-axios'   //追加

Vue.config.productionTip = false

Vue.use(VueAxios, axios)            //追加

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


App.vueにボタンとAPI呼び出しを行う処理を追加します。

  • App.vue内にgetApiData()というAPIを呼び出すメソッドを追加
  • Load APIボタンのクリックでそのメソッドを呼び出すようにしています
  • 結果は、apidata変数に格納され、{{ apidata }}部分に反映されます
<template>
    <div id="app">
        <button type="button" @click="getApiData">Load API</button>
        {{ apidata }}
    </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      apidata: ''
    }
  },
  methods: {
    getApiData() {
      this.axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => (this.apidata = response))
    }
  }
}
</script>


作成したボタンをクリックすると、API呼び出しが行われ、取得できたjsonフォーマットのデータが画面に表示されます。

 { "data": { "time": { "updated": "Jan 31, 2021 07:38:00 UTC", "updatedISO": "2021-01-31T07:38:00+00:00", "updateduk": "Jan 31, 2021 at 07:38 GMT" }, "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org", "chartName": "Bitcoin", "bpi": { "USD": { "code": "USD", "symbol": "&#36;", "rate": "33,735.5254", "description": (続く)


メモ:

Vue.use()ではなく、インスタンスプロパティとしてprototypeに追加しても使えるようです。

Vue.prototype.$axios = axios;
this.$axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => (this.apidata = response))


jsonの整形

jsonデータはドット演算子で読める。また、受信したデータはresponse.dataに入っているようである。

this.axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => (this.apidata = response.data.time))
{ "updated": "Jan 31, 2021 07:39:00 UTC", "updatedISO": "2021-01-31T07:39:00+00:00", "updateduk": "Jan 31, 2021 at 07:39 GMT" } 


あとは、欲しいデータをたどっていけばOK

<button type="button" @click="getApiData">Load API</button><br />
Bitcoin price :  {{ usdrate }}  ( {{ currency }} )
export default {
  name: 'App',
  data () {
    return {
      usdrate: '',
      currency: ''
    }
  },
  methods: {
    getApiData() {
      this.axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => (
        this.usdrate = response.data.bpi.USD.rate,
        this.currency = response.data.bpi.USD.code
      ))
    }
  }
}

画面には以下のように表示された。

Bitcoin price : 33,793.7048 ( USD ) 


jsonデータの一覧表示

取得したデータを一覧表示する。

<button type="button" @click="getApiData">Load API</button><br />
<div
    v-for="currency in apidata"
    v-bind:key="currency"
>
    {{ currency.description }}
    <span v-html="currency.symbol"></span>
    {{ currency.rate_float | currencydecimal }}
</div>
  methods: {
    getApiData() {
      this.axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => (this.apidata = response.data.bpi))
    }
  },
  filters: {
    currencydecimal (value) {
      return value.toFixed(2)
    }
  }

出力。

United States Dollar $ 33740.0195
British Pound Sterling ? 24618.7764
Euro ? 27798.1659 


単にtemplate側にapidata.data.bpi.USDと書いてしまうと、ページのロード直後はapidataにデータが入っていないためエラーとなる。

これを避けるために、axiosのthenメソッド内で値を抽出してやるか、上記の例のようにv-forを使い、データがあるものについてfor文を回すようにしないと値が取得できない。


エラー処理

下記のようなエラーが発生する可能性がある。

エラーの例:

  • APIがダウンしている
  • リクエストが間違っている
  • 戻り値が想定のフォーマットでない


そこで、.catchメソッドを用いてエラーをキャッチする処理を書く。

this.axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => (this.apidata = response.data.bpi))
.catch(error => {console.log(error))


また、ユーザにエラー時メッセージを表示しておくとよい。

<section v-if="errored">
    <p>Sorry, some error happened. Try again later.</p>
</section>
<section v-else>
    (データ表示タグ)
</section>
    return {
      errored: false
    }
      .catch(error => {
        console.log(error)
        this.errored = true
      })


ロード中表示

API呼び出しに時間がかかる可能性があるため、データロード中は「Loading...」などと表示しておきたい。


loadingのような変数を用意し、trueを入れておき、v-ifで「Loading...」を表示。

ロード完了後にloading変数にfalseをセットするとよい。

<div v-if="loading">
    <p>Loading...</p>
</div>
<div
    v-else
    v-for="currency in apidata"
    v-bind:key="currency"
>
    {{ currency.description }} ...
</div>
    return {
      loading : true
    }
      this.axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(response => (this.apidata = response.data.bpi))
      .catch(error => {
        console.log(error)
      })
      .finally(() => this.loading = false)