GAS×スプレッドシート×GlideApps×Slack×Pic2shopで作る書籍管理アプリの実装


概要

今回、知見共有・技術向上意欲の促進を図ることを目的に、社員が会社や個人の所有する書籍の把握を容易にするために書籍管理アプリを作成しました。(あとGASを使ってみたかった😌笑)
GAS(Google Apps Script)を中心に、様々なサービスを連携します。
記事では主要な作業部分のみ解説しています。

構成図

サービス 用途
Glideapps UI/CRUD
Pic2shop バーコードスキャン
Google SpreadSheet データベース
Google Apps Script スクリプト
Slack 通知

完成画面

実際にできたものがこちらです。
https://booklist.glideapp.io/
https://github.com/mgmgmgmi/BookList
※アプリは社内用なので公開していないです…要望があればコピーして公開します。
社内向けのものを作ったので公開しました。

登録画面
バーコードを読み取って書籍を登録できます。

ホーム画面 / 詳細画面 / 編集画面
書籍一覧を閲覧・編集できます。

slack通知
書籍登録時や貸借時にSlackで通知を行います。

開発環境について

今回はclaspを利用しました。
GASのコードとGitを連携してバージョン管理できるスグレモノです。
自分の好きなエディタで実装できるのも嬉しいポイントです。

参考claspを使い、Google Apps Scriptプロジェクトをgitでバージョン管理する - Qiita

実装

1. GAS×スプレッドシートの連携

詳しい解説はコチラ
DB代わりのスプレッドシートのカラムは以下のような構造にしました。

A列目にISBNコードを入力すると、B~F列に書籍情報が登録されます。
書籍の登録時に書籍情報を取得するため、Google Books APIを使用しています。

2. スプレッドシート×GlideAppsの連携

GlideAppsとのサービス連携

GlideApps からGoogleアカウントで認証を行います。
その後、該当のスプレッドシートを指定してGlideAppsのプロジェクトを作成します。


GlideAppsプロジェクトを開くと、ブラウザ上でUIや表示項目などをカスタマイズすることができます。
とても直感的でわかりやすいです。
これでスプレッドシートに対する簡単なCRUD機能が使えるようになります。

参考簡単過ぎる!GoogleスプレッドシートからPWAアプリを開発できる「Glide」を使ってみた! - paiza開発日誌

3. GAS×slackの連携

Slack APIを用いた投稿リクエストの実装

Slackに対する投稿は、Slack APIのchat.postMessageを利用します。
トークンとチャンネルIDは自分のものを確認して記載してください。

Slack.js
function postSlack(text){
  const token = 'hogehoge';
  const channel = 'fugafuga';

  //Slack投稿
  const response = UrlFetchApp.fetch(
    'https://slack.com/api/chat.postMessage?'
    + 'token=' + token
    + '&channel=' + channel
    + '&text=' + encodeURIComponent(text)
  );

  //レスポンス確認
  Logger.log(JSON.parse(response.getContentText())); 
}

ここでの注意点は、textなどパラメータの値に特殊文字等が入っているとGASのバリデーションにかかってエラーになります
そのためencodeURIComponent関数でエンコードを行います。

スクリプトプロパティを利用したトークンの管理

Web APIを利用する際、Slack含めサービスによってはAPIキーなどの認可情報が必要な場合があります。
間違ってGitなどにアップしないように、ローカルでの開発では環境変数や外部ファイルなどに格納することが多いと思います。
クラウドで動作するGASでは環境変数の代わりにスクリプトプロパティという機能を利用します。

GASプロジェクトのメニューから ファイル > プロジェクトのプロパティ > スクリプトのプロパティ を開き、名前と値を入れて保存します。

取得する際には、以下のようにプロパティの名前を指定して値を取得することができます。

Slack.js
  const properties = PropertiesService.getScriptProperties();
  const token = properties.getProperty('SLACK_TOKEN');
  const channel = properties.getProperty('SLACK_CHANNEL');

参考【初心者向けGAS】プロパティストアの概要とスクリプトプロパティの編集方法

4. pic2shop×GASの連携

バーコードの読み取り機能として、Pic2shopというアプリを利用します。
ユーザがバーコード読み取りを行う際、このアプリのダウンロードが必要になります。

カスタムURLスキームによるpic2shopアプリの呼び出し

アプリを起動する場合、カスタムURLスキームを利用します。
Pic2shopでは以下のようなURLでアプリの機能を呼び出します。

pic2shop://scan?callback=(コールバック関数)

コールバック関数の引数として、今回はGETパラメータでGASのWebアプリケーションに渡すことにしました。
バーコードを読み込んだ結果はEANという文字に格納されます。
※pic2shopに渡す際はURLエンコードが必要です。

https://(WebアプリケーションのURL)?isbn=EAN

GladeAppsのリンクから呼び出したかったので、 URL(pic2shop://scan?callback=https%3A%2F%2F...%3Fisbn%3DEAN)をスプレッドシートに記載して表示しました。

参考iPhoneで簡単にバーコードリーダーを作る方法 – 伊藤清徳の垂直落下式ムーンサルトプレス

GASのWebアプリケーションにおけるパラメータ受け取り部分の実装

GlideAppsにAPIなどがあればよいのですが、対応していないため代わりにGASのWebアプリケーションで値を受け取ってスプレッドシートに登録します。

GASのWebアプリケーションを有効化し、GETパラメータを受け取る準備をします。
参考Google Apps Scriptをウェブアプリケーションとして公開する手順

そしてパラメータを受け取るためのトリガーであるdoGet関数を実装します。

Trigger.js
function doGet(e){
  const isbn = e.parameter.isbn;  
  Logger.log(isbn); //確認

  return HtmlService.createHtmlOutput(JSON.stringify(e));
}

ブラウザ等でhttps://(WebアプリケーションのURL)?isbn=EANへアクセスし、GASのログでisbnの値が受け取れていることを確認します。

5. 登録後の画面作成

画面作成と値の受け渡し

Webアプリケーションの画面の作成はHtmlServiceクラスを用います。
GAS <=> HTML間の値の受け渡しは、スクリプトレット(scriptlets)と呼ばれる3つの特別なタグ<? ... ?> <?= ... ?> <?!= ... ?>を利用します。

Trriger.js
function doGet(e){
  const isbn = e.parameter.isbn;

  //GASからスプレッドシートへの書き込み
  addBook(isbn);

  // index.htmlの読み込み
  var htmlTemplate = HtmlService.createTemplateFromFile("index");

  // isbnの値をHTMLへ渡す
  htmlTemplate.isbn = isbn;
  return htmlTemplate.evaluate();
}
index.html
<!DOCTYPE html>
<html>
  <body>
    <p>ISBNコード: <?= isbn; ?> </p>
  </body>
</html>

参考Google Apps Script (GAS)のScriptletsを使って外にあるJavaScriptやCSSを読み込む – CodeAid(コードエイド)

画面レイアウトの変更

最後にHTMLファイルにてBootstrapやCSSの読み込みなどを行います。
Bootstrapの読み込みは公式ドキュメントにある通り、以下を記述して利用します。
<head>タグ内

<head>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>

<body>タグ内の最後の行

<body>
  ...
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>

参考GASでWebページを作成する際にCSSフレームワークBootstrapを導入する方法

CSSの読み込みは、css.htmlファイルを作成したのち、<head>タグ内に以下を記述して利用します。
(.cssはGASの対象外のため、.htmlとして保存します)

<head>
  <?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
</head>
css.html
<style>
body {
    font-family: -apple-system, BlinkMacSystemFont, Roboto, sans-serif
    font-size:14px;
}
</style>

参考GASでWebページを作るときにHTMLとCSSを別ファイルに記述する方法

最後に

細かいカスタマイズは難しいですが、すでにある便利なサービスを組み合わせることで一週間程度で機能の大部分の実装を終えることができました。
ツールを利用することで開発効率を上げられるのはいいなと思いました。
あと単純に実装楽しかったです!笑
記事に間違いや不明な点があれば遠慮なくご指摘ください。