ちゃんと理解できていなかった、「APIを使ってデータ取得する」ことについてまとめました。
APIからデータを取ってきて何かアプリを作ってみたいという方や、
Nuxt.jsでのデータ取得についても書いているので、Nuxt.jsを勉強している方にも読んでもらえると嬉しいです。
今回作成したもの
住所入力フォームでよくある、
郵便番号を入力してボタンを押したら自動で住所を入力してくれるプログラムです。
郵便番号検索APIは登録不要ですぐに使えます。
前提
・Node.jsはインストール済(バージョンは現時点でv10.13.0)
・Vue.js/Nuxt.jsはある程度理解している
(私はVue.js & Nuxt.js超入門で勉強していました。また、こちらの記事も参考にしていただければと思います。)
#作成の手順
- Nuxt.jsのプロジェクトを作成する
- templateを作成する
- 特定の郵便番号の住所データを表示してみる
- 入力された郵便番号の住所データを表示する
- おまけ:エラーメッセージを表示する①
- おまけ:エラーメッセージを表示する②
- おまけ:入力欄をクリックすると初期の画面に戻す
- おわりに
(1)Nuxt.jsのプロジェクトを作成する
プロジェクトを作成したいディレクトリに移動し、以下のコマンドを実行します。
私はDesktopのpracticeというフォルダにsample-search-zipcode-app
という名前のプロジェクトを作成しました。
$ cd Desktop/practice
$ npx create-nuxt-app sample-search-zipcode-app
ProjectNameなど確認する表示が出てきますが、
Choose features to install
以外は初期設定のままEnterを押していって大丈夫です。
Choose features to install
についてはAxiosを選択してEnterを押してください。
installが完了したら、以下のように作成したプロジェクトに移動して実行します。
$ cd sample-search-zipcode-app
$ npm run dev
localhost:3000にアクセスして、以下の画面になっていればプロジェクトの作成は完了です。
(2)templateを作成する
作成したプロジェクトのpagesフォルダのindex.vueファイルを開いて、template部分を作成します。
<template>
<section class="container">
<input type="text" placeholder="郵便番号を入力"/>
<button>住所自動入力</button>
<p>都道府県:</p>
<p>住所1:</p>
<p>住所2:</p>
</section>
</template>
<script>
</script>
最終的には、郵便番号を入力して住所自動入力ボタンを押したら
郵便番号
都道府県
住所1
住所2
が自動で表示されるようにしていきます。
(3)特定の郵便番号の住所データを表示してみる
まずは、入力された郵便番号ではなく、
こちらで指定した郵便番号(今回は〒154-0024)の住所データを表示してみます。
<template>
<section class="container">
<input type="text" placeholder="郵便番号を入力"/>
<button>住所自動入力</button>
<p>{{resultData}}</p>
<p>都道府県:</p>
<p>住所1:</p>
<p>住所2:</p>
</section>
</template>
<script>
const axios = require('axios');
let url = 'http://zipcloud.ibsnet.co.jp/api/search?zipcode=';
export default {
async asyncData() {
let zipcode = '154-0024';
let result = await axios.get(url + zipcode);
return { resultData: result.data.results[0] };
}
}
</script>
もしModule not found
のエラーが出たら、ターミナルで$npm install axios
コマンドを実行して、
再度$npm run dev
してみてください。
-クロスドメイン問題
こんなエラーが出てしまったら、
一旦Chromeを終了して、
$open /Applications/Google\ Chrome.app/ --args --disable-web-security --user-data-dir
コマンドでChromeを開いてください。
このエラーは、ほかのwebサイトからデータを取ってこようとすると制限がかかる
クロスドメイン問題が起こった場合に出ます。
-axiosとは?
axiosは、webサーバーにアクセスして必要な情報をやりとりするための機能です。
(axiosはNuxt.jsのための機能ではなく、Javascriptの一般的なライブラリです。)
const axios = require('axios');
と書くと、axiosを利用できるようになります。
-asyncDataとは?
asyncDataは非同期処理をするためのNuxt.jsのメソッドです。
非同期処理とは、実行できるようになってから実行する処理のことです。今回の場合だと、
http://zipcloud.ibsnet.co.jp/api/search?zipcode=154-0024
にアクセスして
住所データを取得してから、そのあとの処理を行うようにしています。
関数の前にawait
をつけることで、その関数の結果が返ってくるまで待機します。
await
を使う場合は非同期関数を宣言するためにasync
を書いておく必要があります。
−郵便番号検索API
郵便番号検索APIは、日本郵便が提供しているデータを株式会社アイビスが加工して提供しているAPIです。
例えば、〒154-0024の住所データを取得したい場合は、
http://zipcloud.ibsnet.co.jp/api/search?zipcode=154-0024
にアクセスすると
このようにデータを見ることができます。
この結果を変数result
に入れておき、resultData
というプロパティ名で、
今回取得したい住所データ部分result.data.results[0]
をオブジェクトとして返します。
template内では、{{プロパティ名
}}でデータを表示することができます。
(4)入力された郵便番号の住所データを表示する
(3)ではasyncData内でデータ取得しましたが、asyncDataはコンポーネント生成時に自動的に実行されるため、
コンポーネントが表示された際にはすでにデータが表示されています。
これをボタンが押された時に、入力された郵便番号の住所データを表示するように、
data/methodsプロパティを使ってコードを書き換えていきます。
<template>
<section class="container">
<input type="text" placeholder="郵便番号を入力" v-model="zipcode"/>
<button @click="searchAddressInfo">住所自動入力</button>
<p>都道府県:{{addressData['address1']}}</p>
<p>住所1:{{addressData['address2']}}</p>
<p>住所2:{{addressData['address3']}}</p>
</section>
</template>
<script>
const axios = require('axios');
let url = 'http://zipcloud.ibsnet.co.jp/api/search?zipcode=';
export default {
data() {
return {
zipcode: '',
addressData: {}
}
},
methods: {
searchAddressInfo() {
axios.get(url + this.zipcode).then((res) => {
this.addressData = res.data.results[0];
})
}
}
}
</script>
154-0024
と入力→住所自動入力ボタンを押して、このような画面になっていたらOKです。
-実装の流れ
dataプロパティに`zipcode`を用意して、入力された郵便番号とバインドします。 また、住所自動入力ボタンをクリックした時に`searchAddressInfo`を呼び出します。 そしてdataプロパティに`addressData`を用意して、 `searchAddressInfo`の中でAPIから取ってきた住所データを入れます。 最後に、`addressData`の`address1` `address2` `address3` プロパティの値を それぞれtemplate内で表示します。-get.then
`searchAddressInfo`の中では、get.thenを使ってデータを取得しています。 get.thenは以下の形で使うことができ、`res`の中に取得したデータが入っています。axios.get( URL ).then((res) => { アクセス後の処理 });
おまけ:エラーメッセージを表示する①
正しい郵便番号が入力されなくてデータが取得できなかった場合に、
no data
とメッセージを表示するようにします。
<template>
<section class="container">
<p>{{message}}</p>
<input type="text" placeholder="郵便番号を入力" v-model="zipcode"/>
<button @click="searchAddressInfo">住所自動入力</button>
<p>都道府県:{{addressData['address1']}}</p>
<p>住所1:{{addressData['address2']}}</p>
<p>住所2:{{addressData['address3']}}</p>
</section>
</template>
<script>
const axios = require('axios');
let url = 'http://zipcloud.ibsnet.co.jp/api/search?zipcode=';
export default {
data() {
return {
zipcode: '',
addressData: {},
message: ''
}
},
methods: {
searchAddressInfo() {
axios.get(url + this.zipcode).then((res) => {
if(res.data.results == null) {
this.message = 'no data'
return;
}
this.addressData = res.data.results[0];
})
}
}
}
</script>
dataプロパティにmessage
を用意して、
もしデータが取得できていなかったら(取得したデータがnullだったら)message
をno data
とします。
例えば、1
とかa
とか間違った郵便番号を入れてno data
と表示されていたらOKです。
おまけ:エラーメッセージを表示する②
URLが間違っていたり、サーバーが停止してしまうなど、アクセスできなかった場合に
error
とメッセージを表示するようにします。
get.thenのあとに、さらにcatchメソッドを追加してエラー処理をします。
<template>
<section class="container">
<p>{{message}}</p>
<input type="text" placeholder="郵便番号を入力" v-model="zipcode"/>
<button @click="searchAddressInfo">住所自動入力</button>
<p>都道府県:{{addressData['address1']}}</p>
<p>住所1:{{addressData['address2']}}</p>
<p>住所2:{{addressData['address3']}}</p>
</section>
</template>
<script>
const axios = require('axios');
let url = 'http://zipcloud.ibsnet.co.jp/api/search?zipcode=';
export default {
data() {
return {
zipcode: '',
addressData: {},
message: ''
}
},
methods: {
searchAddressInfo() {
axios.get(url + this.zipcode).then((res) => {
if(res.data.results == null) {
this.message = 'no data'
return;
}
this.addressData = res.data.results[0];
}).catch((error) => {
this.message = 'error'
})
}
}
}
</script>
例えば変数urlの適当な1文字を削除して、正しい郵便番号を入力してerror
と表示されていればOKです。
おまけ:入力欄をクリックすると初期の画面に戻す
最後に、住所データが表示されている状態で入力欄をクリックした時に、初期の画面に戻すようにします。
<template>
<section class="container">
<p>{{message}}</p>
<input type="text" placeholder="郵便番号を入力" v-model="zipcode" @focus="focus"/>
<button @click="searchAddressInfo">住所自動入力</button>
<p>都道府県:{{addressData['address1']}}</p>
<p>住所1:{{addressData['address2']}}</p>
<p>住所2:{{addressData['address3']}}</p>
</section>
</template>
<script>
const axios = require('axios');
let url = 'http://zipcloud.ibsnet.co.jp/api/search?zipcode=';
export default {
data() {
return {
zipcode: '',
addressData: {},
message: ''
}
},
methods: {
searchAddressInfo() {
axios.get(url + this.zipcode).then((res) => {
if(res.data.results == null) {
this.message = 'no data'
return;
}
this.addressData = res.data.results[0];
}).catch((error) => {
this.message = 'error'
})
},
focus() {
this.zipcode = ''
this.addressData = {}
this.message = ''
}
}
}
</script>
inputに@focus
を追加し、入力欄をクリックした時にfocus
メソッドを呼び出し、
dataプロパティをすべて初期化します。
住所データが表示されている状態で入力欄をクリックしてみて、初期の画面に戻っていればOKです。
おわりに
引き続きNuxt.jsなどの勉強がんばりたいです。
もし間違った記載などあればご指摘いただけると幸いです。
参考
・Vue.js & Nuxt.js超入門
・【Nuxt.js】todoアプリを作成してみた①
・【Nuxt.js】todoアプリを作成してみた②
・JavaScriptの非同期処理を並列処理と勘違いしていませんか?
・async/await 入門(JavaScript)
・【解説付き】chromeでXMLHttpRequestをローカルのファイルで行う方法
・郵便番号検索API