Vue.jsでWebサービス開発 ⑩ランダム表示API GoogleAppsScriptとaxios

目次

GitHub

今回の作業が終了した後のブランチはこちらです。

https://github.com/skliber/excursion-demo/tree/random

要件

ボタンをクリックしたら動物か職業がランダムに表示される

これを実現するにはGoogle スプレッドシートGoogle App Scriptを使います。

Googleスプレッドシートに新しいシートを追加

  1. 動物と職業のリストを集めます。
    開発時はネットをクロールして集めました。もし自分でやる場合は相手のサーバーに迷惑がかからないように行ってください。
    データを集めたら1行に1つの名前が入るように加工します。
    動物の場合、読めない漢字があったので全てカタカナに変換しました。
    やってられんという方は下記のリストをそのまま使用できます。
    リスト
    animal.txt GitHub
    work.txt GitHub
  1. Google スプレッドシートに移動して新しく空白のシートを追加します。

  2. 1で集めたリストをAの列に書いていきます。
    コピペでいけるはずです。動物と職業はそれぞれ別のシートで作成してください。

スクリプトの実装

リストをランダムに出力するAPIを作ります。動物シートと職業シートで同じ作業をしてください。

  1. スプレッドシートのメニューから「ツール」→「スクリプトエディタ」をクリックします。

  2. スクリプトエディタが開くので以下のコードを貼り付けます。

    function doGet(e) {
     var ss = SpreadsheetApp.getActiveSpreadsheet();
     var sheet = ss.getSheetByName('シート1');
     var random_id = Math.floor( Math.random() * 1263 + 1 );
     var data = sheet.getRange('A'+random_id).getValue();
     return ContentService.createTextOutput(JSON.stringify(data)).setMimeType(ContentService.MimeType.JSON);
    }
    

    function doGet(e)

    GETリクエストが来たときの処理を定義するメソッドです。

    SpreadsheetApp.getActiveSpreadsheet(); & ss.getSheetByName(‘シート1’);

    現在のシートを取得します。

    Math.floor( Math.random() * 1263 + 1 );

    シートの行数を考慮してランダムな数値を生成しています。

    sheet.getRange(‘A’+random_id).getValue();

    シートのA列から先ほど作ったランダムな数値に対応するセルを取得します。

    ContentService.createTextOutput(JSON.stringify(data)).setMimeType(ContentService.MimeType.JSON);

    取得したデータを返答します。

  3. 「公開」→「ウェブアプリケーションとして導入」をクリックします。
    以下のように設定して「導入」ボタンを押します。アプリケーションにアクセスできるユーザーは一応全員にしておきます。

  4. スクリプトの承認を行います。
    導入ボタンを押すとこのような表示が出てきますので許可します。

    許可ボタンを押すとこうなりますが、これは詳細をクリックしてください。

    詳細を押すと下部に「<スクリプトの名前>(安全ではないページ)に移動」が出てきますのでこれをクリックします。

    最後にこのような許可画面になりますので「許可」をクリックして完了です。

  5. APIとなるURLをコピーします。
    承認できれば「このプロジェクトをウェブ アプリケーションとして導入しました。」という表示と共にURLが出力されますので、
    これをどこかにメモしておきます。

これでAPIは完成しました。先ほどのURLをブラウザで開けば動作確認ができます。
ブラウザ上に名前が1つだけ表示されていれば成功です。

Vueでの実装

先ほど作ったAPIをVue.jsから叩きます。
axiosを使用します。

手順

  1. ターミナルで$ npm install --save axiosを実行します。

  2. src/components/Some.vueを以下のように変更します。

  • template

    <template>
      <el-row :gutter="20" type="flex" justify="center">
        <el-col :xs="24" :sm="24" :md="14" :lg="14" :xl="14" class="disable-col-padding">
          <el-col :span="24">
            <h4 class="stop-bottom-margin">テーマと関係ないものを入力してください</h4>
            <p class="text-small stop-top-margin">動物、職業、場所、映画、小説、食べ物、横にあったもの etcetc...</p>
            <el-input placeholder="テーマと関係ないもの" v-model="some" v-loading="loading"></el-input>
          </el-col>
          <el-col :span="24">
            <p class="text-small">動物と職業はランダムで出力することもできます。チェックしてランダム表示ボタンを押してください</p>
            <el-checkbox v-model="animal" label="動物" border></el-checkbox>
            <el-checkbox v-model="work" label="職業" border></el-checkbox>
          </el-col>
          <el-col :span="24">
            <el-button v-on:click="refreshSome" type="success" icon="el-icon-refresh">ランダム表示</el-button>
          </el-col>
        </el-col>
      </el-row>
    </template>
    

    v-loading=”loading”

    ボタンをクリックすると少しだけロード時間が発生しますので、ユーザーにロード中であることがわかるようにします。v-loadingはElementUIで使用できるカスタムディレクティブです。

    el-checkbox v-model=”animal” & v-model=”work”

    el-checkboxはElementUIのチェックボックスです。この値はv-modelでバインドします。

    el-button v-on:click=”refreshSome”

    ランダム表示をするためのボタンです。今までの機能とは違うので色を変えました。

  • script

    <script>
    import axios from 'axios'
    
    export default {
      data () {
        return {
          animal: false,
          work: false,
          loading: false
        }
      },
      computed: {
        some: {
          get () { return this.$store.getters.some },
          set (value) { this.$store.dispatch('doSomeUpdate', value) }
        }
      },
      watch: {
        some: {
          handler: function (some) {
            if (some) {
              this.loading = false
            }
          },
          deep: true
        }
      },
      methods: {
        refreshSome: function () {
          this.loading = true
          let animalApi = 'https://script.google.com/macros/s/AKfycbzq8Ow2oQ2eGcNNSRVNHmzT-P1MbSNUbvrZ-wTjhbSvJ-oxmbJy/exec'
          let workApi = 'https://script.google.com/macros/s/AKfycbzYFSKk8GF_QmSxPXs1vnsaAUyL3FyRBNrI9tDgcEjXpqVhA_U/exec'
          let url = ''
          if ((this.animal && this.work) || (!this.animal && !this.work)) {
            const randomBoolean = Math.random() >= 0.5
            if (randomBoolean) {
              url = animalApi
            } else {
              url = workApi
            }
          } else if (this.animal) {
            url = animalApi
          } else {
            url = workApi
          }
          axios
            .get(url)
            .then(
              function (response) {
                this.some = response.data
              }.bind(this)
            )
            .catch(function (e) {
              console.error(e)
            })
        }
      }
    }
    </script>
    

    data ()

    animal,work,loadingを全てfalseで追加しています。

    watch

    算出プロパティのsomeを監視しています。someが存在すればAPIから値を受け取れたと判断してローディングの表示を解除します。

    refreshSome: function ()

    「ランダム表示」ボタンが押されたときの処理です。少々リファクタリングの余地がありそうですが、チェックボックスの値を見てif文で場合分けを行い、axiosで該当するAPIにGETリクエストを投げています。これで値が取れたらsomeにデータを入れます。

作業結果
src/components/Some.vue GitHub

動作確認

お疲れ様でした。これでGASを使用してアイデアのもとをランダムに表示することができるようになりました。
$ npm run devを実行してhttp://localhost:8080/を開き、Some画面でランダム表示ボタンを押してみましょう。
チェックボックスの値に応じて何らかの名前がフォームに入れば成功です。

余談

最初はボタンを押してから表示されるまでの時間を考えて、ローカルにJSONを作って読み込めば良いと考えていました。
そこで1000行超のJSONを作って読んでみたらブラウザがメモリリークを起こしてフリーズしました。ご注意ください。

参考

ElementUI loading
3分で API を作って世の中にデプロイするライブコーディング〜今日から君もスピードスターエンジニア〜

next

GASを使用してアイデアのもとをランダムに表示しました。
次回はサービスロゴを作成します。