GAミント至上主義

Web Monomaniacal Developer.

Google Apps Scriptのウェブアプリでaxiosでリクエストする時にハマったメモ

シニアジョブで簡単な来客記録システムを作りあたり、Google Workspaceを使っているので、
NuxtJSでUI作って、Google スプレッドシートとGASでいけるんじゃね?
と思ってやってみたら、ちょっとハマったものの出来たのでメモ。

f:id:uyamazak:20210218134626p:plain
※画面は開発中のものです(圧倒的いらすとや感)

NuxtJSの方は今回は省略。

結論

設定ちゃんとすれば、普通のURLに普通のリクエストでスプレッドシートに書き込むようなAPIが簡単にできる。
認証エラーでもCORSエラーになる罠に気をつける。

ログを書き込むスプレッドシートをつくる

特に何の変哲もないやつ作ります。
f:id:uyamazak:20210218132559p:plain

スクリプトを書く

ツール → スクリプトエディタ でGASの入力画面へ。

今回はGETリクエスト使うのでdoGet()という名前にする必要があります。

詳細は公式。GAS関係は結構デタラメな古い情報が検索に溢れているので注意しましょう。
https://developers.google.com/apps-script/guides/web


名前、会社名とかをGETパラメーターで受け取るようにして雑にこんな感じになりました。
認証とかライブラリインストールとか省けるのでいいですね。
空白行とかできるとアレなので簡単に有無チェックだけはしておきます。

function doGet(e) {
  const ss = SpreadsheetApp.getActive().getSheetByName('来客ログ');
  if (!e) {
    return ContentService.createTextOutput('{result:"NG", error: "eventがありません"}')
  }
  const params = e.parameter
  const name = params.name
  if (!name) {
    return ContentService.createTextOutput('{result:"NG", error: "nameは必須です"}')
  }
  const description = params.description
  if (!description) {
    return ContentService.createTextOutput('{result:"NG", error: "descriptionは必須です"}')
  }
  const company = params.company

  ss.appendRow([new Date(), company, name, description]);
  return ContentService.createTextOutput('{result:"OK"}');
}

デプロイでウェブアプリを選択

デプロイには実行可能 APIウェブアプリの2つがあり、名前的に実行可能 APIの方かな?と思ったけど404になってだめでした。
ウェブアプリの方でした。

アクセスできるユーザーを"全員"にする

この画面で全員にしておかないと認証画面にとばされaxiosでCORSエラーになります。
開発者ツールでリクエストをよく見れば分かるものの、認証エラーではなくCORSエラーで来るのが曲者でした。
f:id:uyamazak:20210218133543p:plain

全員と社内だとURLが変わるので注意しましょう。
また設定変更後デプロイしないと反映されません。

axiosでリクエストする

今回はNuxtJSだったのでプラグインでメソッドを生やしました。
上記で取得したURLはnuxt.config.jsのenvに追加。
あとは必要なパラメーターをつけるだけ。

plugins/gas-api.js

import axios from 'axios'
async function addSpreadSheet(name, company, description) {
  await axios.get(`${process.env.gasApiUrl}`, {
    params: { name, company, description },
  })
}

export default (_, inject) => {
  inject('addSpreadSheet', addSpreadSheet)
}

あとはコンポーネントのmethodsでこんな感じのを追加して使いました。

send() {
      this.$refs.form.validate()
      this.isLoading = true
      if (this.valid) {
        // 送信処理
        try {
          await this.$addSpreadSheet(this.name, this.company, 'テスト')
        } catch(e) {
          this.isLoading = false
          this.$router.push('error')
          return
        }
        this.isLoading = false
        this.$router.push('thanks')
      }
    },