AppSheetと16行のGoogle Apps Scriptで作るバーコード蔵書管理アプリ（画面の再読み込みが必要）

この記事は、[AppSheetからApps Scriptを直接呼び出せる](https://developers-jp.googleblog.com/2022/05/apps-script-connector-for-appsheet.html)ようになる**前**に書きました。新しい記事では、画面の再読み込みが不要になっています：

https://qiita.com/takatama/items/8c4f7f657d9925cde57f

以下は、AppSheetからApps Scriptを呼び出さずに実現する方法です。

GoogleのノーコードツールAppSheet、Googleスプレッドシート、Google Apps Scriptを組み合わせて、蔵書管理アプリを無料で作りました。スマホのカメラを使い、バーコードを読むだけでじゃんじゃん登録できるのでとても便利です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/e2e8ef8e-0afb-ff6d-e8a2-5ea0a401e3a8.png)

この記事を書くにあたって、[ノーコード(AppSheet)でバーコードを読み取ってGASを使った蔵書管理](https://qiita.com/nyanko5656/items/351a23d636e29e4c4438)を参考にさせていただきました。どうもありがとうございます！

今回はWebhookを使わないシンプルな構成で実現してみました。[Google SheetsのChangeイベント](https://developers.google.com/apps-script/guides/triggers/events#change)を使っています。画面の再読み込みが必要なこともありますが十分実用的です。

# Googleスプレッドシートの準備

「AppSheetを使うには、まずスプレッドシートから」

AppSheetの特徴は、先にデータソースを作るところにあります。
書誌情報を取得するのに利用している [OpenBD API](https://openbd.jp/#first) のsummaryが次のような形式になっているので、

```json
"summary": {
  "isbn": "9784873115658",
  "title": "リーダブルコード : より良いコードを書くためのシンプルで実践的なテクニック",
  "volume": "",
  "series": "",
  "publisher": "オライリー・ジャパン : オーム社",
  "pubdate": "2012-06",
  "cover": "https://cover.openbd.jp/9784873115658.jpg",
  "author": "Boswell,Dustin／著 Foucher,Trevor／著 角征典／翻訳 フォシェトレバー／著 ほか"
}
```

それに合わせてGoogleスプレッドシートで、次のようにカラムを設計しました。なお、最初にID列を作ったのは、AppSheetでいい感じに動かすための工夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/36e8ca9a-fb85-2a0f-65b6-b41e1a4c560a.png)
シート名は```Books```にします。もし、別のシート名だとエラーが出て使えないので注意してください。

# Google Apps Scriptの準備

スプレッドシートに新しいISBNが登録されることをトリガーとして、そのISBNにひもづく書誌・書影情報をOpenBD APIで取得します。

Googleスプレッドシートのメニュー Tools > Script Editor で記述していきます。

```javascript
function fetchBookSummary(isbn) {
  const url = 'https://api.openbd.jp/v1/get?isbn=' + isbn;
  const res = UrlFetchApp.fetch(url);
  const json = JSON.parse(res.getContentText());
  return json[0].summary;
}

function onChangeSheet(e) {
  const sheet = SpreadsheetApp.getActive().getSheetByName('Books');
  sheet.getDataRange().getValues().forEach((row, i) => {
    const isbn = row[1], title = row[2];
    if (!isbn || title) return;
    const s = fetchBookSummary(isbn);
    sheet.getRange(i + 1, 1, 1, row.length).setValues([[row[0], isbn, s.title, s.publisher, new Date(s.pubdate), s.cover, s.author, row[7]]]);
  });
}
```

```fetchBookSummary()``` は、UrlFetchAppを使って OpenBD API を呼び出しsummaryを返却します。

```onChangeSheet()``` は、スプレッドシートが変更されたときに呼び出します。Booksシートのデータをすべて読み込み、ISBN列にデータはあるけれど、タイトル列にデータがない場合に、```fetchBookSummary()``` を使って書誌情報を取得し、スプレッドシートに書き戻します。

## 忘れずにトリガーを設定

ソースコードの準備ができたら、スプレッドシートを変更したときに ```onChangeSheet()``` を呼び出すようにトリガーを設定します。Script Editorの左ペインの時計マーク Triggersを選択し、右下の Add Trigger ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/11d6919c-6602-acc7-3c0f-c1f393171e57.png)

Select event type を On change にしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/58a5320c-56d0-65f1-899b-68bea5b496b9.png)

ここまで準備ができたら、ISBN列に例えば```9784873115658```を入力してみましょう。少し時間が立つと、自動的に書誌情報が表示されます。

# AppSheetの準備

ここまででスプレッドシート側の準備ができました。
スプレッドシートのメニュー Tools > AppSheet > Create an app で、AppSheetのアプリを作ります。
AppSheet側でいい感じに準備をしてくれますが、間違って解釈していないか調整していきます。

## AppSheetのデータスキーマを確認

まずはデータが肝心です。

AppSheetがBooksテーブルを自動的に作ってくれています。細かい調整をするために、左ペイン Data > 上部タブ Columns を開きます。最終的には次のようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/5a63b42d-de45-0959-5e4e-b3c133657a92.png)

私は次のような調整をしました。

- ID
    - SHOW?とSEARCH?を外して、入力画面から見えなくする
- ISBN
    - TypeはNumberからTextに変更する
    - REQUIRE?をチェックする
    - SCAN?をONにして、バーコードリーダーを有効にする
- PubDate
    - REQUIRE?を外す
    - INITIAL VALUEがTODAY()だったので消す
- Cover
    - TypeをThumbnailに変更して、書影を表示する
    - REQUIRE?を外す
- Created At
    - TypeをTextからDateTimeに変更する
    - INITIAL VALUEをNOW()にする

## AppSheetのViewを確認

次に画面を見ていきます。Booksビューを作ってくれています。左ペイン UX > 上部タブ Views を開いて調整していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/57973f25-0152-b89f-c318-e0e60b4ccf60.png)

- View type
    - cardをdeckに変更します
- View Options
    - Sort byでPubDateが有効になっていたので削除しました

## AppSheetのアプリプレビューを確認

ColumnsとViewsを確認したら、画面右側のプレビューを確認します（もしプレビュー画面が見えていない場合は、画面右はじにある左向きの三角マークを押してください。）。

といっても、プレビューではバーコードリーダーが使えないので、確認できるのは一部です。

もし、次のエラーが出ていたら、シート名が```Books```になっているか、確認してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/f2c6eca4-be6d-31eb-fc23-6728ab4ea636.png)

うまく設定できていれば、次の画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/33b86522-1c52-8042-88cf-3f005a0fb552.png)

プレビュー画面の右下にあるプラスボタンを押すと、本の登録フォームが表示されます。この時、ISBNの欄の右はじにQRコードアイコンが表示されていることを確認してください（もし表示されていなければ、ColumnsのSCAN?をチェックしてください）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/1ce8a969-3d1a-7be3-fd00-4f5f8be0c393.png)

手入力でISBNを入力したときに、正しく情報が取得できるかを確認します。ISBNの欄に```9784873115658```を入力して、プレビュー画面下のSaveを押します。

すると、ISBNだけが登録された状態になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/11249817-03e7-168a-2b53-89cb0e8fe5fc.png)

そのまま待っていると書誌情報が表示されます。タイミングによってはプレビュー画面が更新されないことがあるので、画面が変わらない場合は右上の回転矢印アイコンを押して再読み込みしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/19bed52f-c471-db2a-3568-02a5d7e90a7f.png)

## スマホアプリで確認

プレビューでの動作を確認できたら、いよいよスマートフォンのカメラを使って試してみます。
アプリストアから AppSheet アプリをインストールしてログインし、左上のメニューから Created by me を選ぶと自分が作ったアプリ一覧が表示されます。

プレビューと同じように、右下のプラスアイコンを押して、ISBNの欄のQRコードアイコンを押すとカメラが起動します。本には2つのバーコードがついていますが、上の方（978からはじまるISBN）を読み取ります。ISBNの欄に978からはじまる数字が入力されたら、Saveボタンを押してください。私の環境では5秒程度で本の情報が表示されました。

# まとめ

次の手順で無料の蔵書管理アプリを作ってみました。

- Googleスプレッドシート
    - データ構造を決める
    - Web APIで情報を取得し、スプレッドシートに反映するGoogle Apps Scriptを作る
    - スプレッドシートに情報が入力されたら、上記スクリプトを実行するトリガーを作る
- AppSheet
    - 上記スプレッドシートからアプリを作る
    - プレビューでバーコードリーダー以外の動作を確認する
    - スマホにAppSheetアプリをインストールして動作確認する

スプレッドシートのChangeイベントを使うことで、Webhookを使わない構成にできました。Webhookのエンドポイントを公開せずにすむので安心です。

バーコードを使うアプリを、こんなに簡単に作ることができて驚きです。スマホでデータベースを確認したい、といった単純な用途にAppSheetはピッタリですね！

## 2022/02/23 追記

- もし、バーコードを連続して読み取りたい場合は次のスクリプトを参考にしてください。AppSheetほどではありませんが、ごく簡単なスクリプトで実現できます。

https://qiita.com/takatama/items/5ef6b31c4f228f0393e1