理系公務員のプログラミング日記

Vue3で非同期処理を利用して楽天APIから本のデータを取得する

タグ:
vue3
授業課題の解説

楽天APIを叩く

楽天API一覧

楽天APIには初期設定が必要ですが、それは割愛。

JavaScriptで楽天APIから本のデータを取得する

JavaScriptでAPIからデータを取得するには、一般的に非同期関数を利用します。

楽天ブックス総合検索APIから、 キーワードに「JavaScript」を指定したAPIを呼び出してみます。

【ハンズオンJavaScript】非同期処理で気象庁のAPIから天気予報データを取得するで書いたように、 難しいことは考えず、非同期処理のfetchawaitキーワードをつけて、それを包む関数にasyncキーワードを追加します。

const rakuten_book_api = "楽天ブックスの本からJavaScriptが名前に含まれている本を検索するAPIのurl" const getData = async (url) => { const response = await fetch(url); const data = await response.json() return data } const book_data = getData(rakuten_book_api) console.log(book_data)

楽天ブックスAPIから取得できるデータの中身はこんな感じで、 Items配列の中にItemオブジェクトが並んでおり、 その中に本のタイトルや著者、ISBN番号などの情報かオブジェクトの形で入っています。

楽天ブックスAPI結果

Vue.jsから楽天APIで本のデータを取得する

上記のことをvue.jsで応用します。

サンプルとしてBooksコンポーネントを作り、その中で楽天ブックスAPIを叩いてみました。

vue.jsのcreatedまたは、mountedにfetchメソッドを含ませることで APIからデータを取得できます。

違いについてはこちらが参考になりますが、少し難しいので悩むならmountedにしとけば良いんじゃないかな(雑)。

Vuejs APIアクセスはcreatedとmountedのどちらで行う?

APIからの取得データには本の画像が入っているので、imgタグのsrc属性v-bindで、画像のurlを設定しています。

Book.vue

<template> <div> <h2>{{ book_title }}</h2> <img v-bind:src="book_image" alt=""> </div> </template> <script> export default { name: "Book", data: () => ({ book_title: "", book_image: "" }), async mounted() { const url = '楽天ブックスAPIのアドレス' const response = await fetch(url); const data = await response.json() console.log(data.Items[0]) const first_item = data.Items[0].Item this.book_title = first_item.title this.book_image = first_item.largeImageUrl } }; </script>

楽天ブックスAPIの本のタイトルと画像

APIから取得したデータ全てをv-forを利用して表示する

APIから取得してItemsは配列なので、v-forで分解して利用することを考えます。

こういったAPIから取得したデータはオブジェクトを複数持った配列という形で流れてくることが頻繁にあります。

そのため、データが格納された配列を分解し各コンポーネントにオブジェクトを渡す処理が、アプリケーションを作成する際には頻出します。この処理の流れはぜひマスターしてください。

まず、APIにアクセスする処理を親のApp.vueコンポーネントに移し、v-forで分解し、子のBookコンポーネントではpropsとして受け取ります。

App.vue

<template> <div class="container"> <Book v-for="book_data in book_list" v-bind:book_data="book_data" v-bind:key="book_data" /> </div> </template> <script> import Book from "./components/Book.vue"; export default { name: "App", components: { Book, }, data: () => ({ book_list: "", }), async created() { const url = "楽天ブックスAPIのアドレス"; const response = await fetch(url); const data = await response.json(); this.book_list = data.Items; }, }; </script> <style > .container { display: grid; grid-template-columns: 1fr 1fr 1fr; width: 450px; } </style>

Book.vue

<template> <div style="display: flex"> <div style="width:300px; margin:10px;"> <h3>{{ book_title }}</h3> </div> <img v-bind:src="book_image" alt="" style="margin:10px"/> </div> </template> <script> export default { name: "Books", props: { book_data: Object, }, data: () => ({ book_title: "", book_image: "", }), mounted() { this.book_title = this.book_data.Item.title; this.book_image = this.book_data.Item.largeImageUrl; }, }; </script>

本のタイトルと画像たち