今から10分ではじめる Google Apps Script(GAS) で Web API公開

今から10分ではじめる Google Apps Script(GAS) で Web API公開:


概要


  • Google Apps Script (GAS)で、Web API(無料、サーバーレス)を公開する方法についてのメモです

  • Google Apps Script (GAS)をローカルで開発したい、Gitでコード管理したい、クラスを使いたい、TypeScriptを使いたい、などのやり方も後半簡単に紹介します


Google Apps Script (GAS) の位置づけを理解してみる



image.png


  • Google Apps Script はG Suite(GmailやスプレッドシートなどGoogleサービス)を JavaScriptで制御できる仕組み。だから、Microsoft OfficeのVBAのGoogleサービス版みたいな感じ。
  • JavaScriptで書いた処理をWebAPIとして公開できるので、AWS LambdaとかGoogle Functionのようなサーバレスなコード実行環境のようにも使える←今回はこの用途で使いたい
  • JavaScript 1.6(2005年11月)がベースでかつブラウザ系機能であるDOM API等は無いが、ツールをこねくり回せば今風なコードを書くこともできる。
  • 従量課金のような考え方ではないので、お金を払っても無限に使えるわけではない。容量制限がある。


Google Apps Script のプロジェクトを作る


Google Apps Scriptのトップページにいく

Googleアカウントにログインした状態で以下に行く

https://script.google.com



image.png



最初のプロジェクトを作る



image.png


[APPS SCRIPTを作成]をクリックすると、プロジェクトが作成される。

無題のプロジェクト というプロジェクトとコード.gsというファイルができるので、



image.png


画面左上の無題のプロジェクトをクリックして、プロジェクト名をwebapi_example01に変更した。

さらに、↓のように、


image.png


左側ペインにコード.gsというファイルがあるのがわかる。これが最初のファイルとなる。ファイル名の右にある[▼]を押してメニューから名前を変更をクリックしてmain.gsというファイル名に変更した。



image.png



コードを書いてWeb APIを公開する

さっそくコードを書いて、WebAPIを公開する。コードはJavaScriptで書く。

Google Apps Script はJavaScriptの最新をサポートしているわけでも、すべての機能をサポートしているわけでもないが、JavaScriptが書ける人ならなんとかなる。


Web APIをつくる

デフォルトだと以下のようになっているが、Web APIとして公開したいので、GETやPOSTをハンドリングできるようにする。

main.js
function myFunction(){ 
} 
関数myFunctionは消して、以下のようにした

main.js
//HTTP GETをハンドリングする 
function doGet(e) { 
 
    //リクエストパラメータ名"text"の値を取得する 
    var text = e.parameter.text; 
    var value; 
    if (text) { 
        value = "You say " + text; 
    } else { 
        value = "Please say something!"; 
    } 
    var result = { 
        message: value 
    } 
 
    var out = ContentService.createTextOutput(); 
 
    //Mime TypeをJSONに設定 
    out.setMimeType(ContentService.MimeType.JSON); 
 
    //JSONテキストをセットする 
    out.setContent(JSON.stringify(result)); 
 
    return out; 
} 
 
シンプルなコードだが、いくつかみておく。

コード中のdoGetで渡される引数eは、リクエストパラメータ等のイベントパラメータが入る。

function doGet(e) { 
var text = e.parameter.text; 
e.parameterはリクエストパラメータがkey/valueペアとして入るので、

Google Apps ScriptでWeb公開したURLでhttps://xxxxxx/exec?text=Helloとリクエストされたら e.parameter.textには"Hello"が入ることになる。

リクエストパラメータについて詳しくはこちらに書いてある。

以下の ContentService はテキストコンテンツを返すためのサービスで #createTextoutput で Textoutputオブジェクトを生成する。

var out = ContentService.createTextOutput(); 
Textoutputオブジェクト outに対して #setMimeTypeでJSONを指定し、#setContentで実際に返すテキスト(この場合は JSON形式のテキストにして)をセットする。

out.setMimeType(ContentService.MimeType.JSON); 
out.setContent(JSON.stringify(result)); 
return out; 
これでTextoutputオブジェクト outを return すればOK。

セキュリティを考慮してスクリプトがダイレクトにテキストをブラウザに返すことはなく、実際には、ブラウザは googleusercontent.com にリダイレクトされ、そこから結果を受け取る、という構造になっている。



image.png


これで、GETメソッドでアクセスすると、JSONを返すWeb APIができた。

早速公開してみる。


Web APIの公開

上部メニューから公開>Webアプリケーションとして導入 を選択する。



image.png


するとダイアログがでる、


image.png


アプリケーションにアクセス出来るユーザーを 全員(匿名ユーザーを含む) にする

image.png

[導入]をクリックすると、現在のウェブアプリケーションのURLが表示されるので、そのURLをコピーしてブラウザからアクセスしてみる。



image.png


アクセス結果



image.png


無事、レスポンスが返ってきた。

シンプルだけど、これでWeb API公開に成功した。


ブラウザからこのAPIをたたきたい

ブラウザからAPIをたたくということは、まずクロスドメイン大丈夫か?ということが頭をよぎる。

つまりGoogle Apps Script で公開したWeb APIはCORS(Cross-Origin Resource Sharing)を OKにできるのか?

→Google Apps Script で公開したWeb APIはCORSできない

つまり異なるドメイン(オリジン)からAjaxはGETもPOSTもできない。

ブラウザ上で動くスクリプトからAjax的に使いたければ、同じドメインにHTMLを配備するか、別ドメインにHTMLを配備したうえで、JSONPを使うしか手がないようだ。


Web APIをJSONP対応化する

ということで、別ドメインにHTMLを置く前提でさきほどのコードをJSONPに書き換える

main.js
//HTTP GETをハンドリングする 
function doGet(e) { 
 
    //リクエストパラメータ名"text"の値を取得する 
    var text = e.parameter.text; 
 
    var value; 
 
    if (text) { 
        value = "You say " + text; 
    } else { 
        value = "Please say something!"; 
    } 
 
    var result = { 
        message: value 
    } 
 
    var responseText; 
 
    var out = ContentService.createTextOutput(); 
 
    var callback = e.parameter.callback; 
 
    if (callback) { 
        responseText = callback + "(" + JSON.stringify(result) + ")"; 
        //Mime Typeをapplication/javascriptに設定 
        out.setMimeType(ContentService.MimeType.JAVASCRIPT); 
 
    } else { 
        responseText = JSON.stringify(result); 
        //Mime Typeをapplication/jsonに設定 
        out.setMimeType(ContentService.MimeType.JSON); 
    } 
 
 
    //JSONPテキストをセットする 
    out.setContent(responseText); 
 
    return out; 
} 
 
var callback = e.parameter.callback; 
 
    if (callback) { 
        responseText = callback + "(" + JSON.stringify(result) + ")"; 
        //Mime Typeをapplication/javascriptに設定 
        out.setMimeType(ContentService.MimeType.JAVASCRIPT); 
 
    } else { 
        responseText = JSON.stringify(result); 
        //Mime Typeをapplication/jsonに設定 
        out.setMimeType(ContentService.MimeType.JSON); 
    } 
 
リクエストパラメータに callbackがついていたら、JSONPで返すようにした。

本家サイトにも注意があるが、JSONPをつかうなら脆弱性に関して注意深く設計する必要がある。提供する情報はリードオンリーかつ誰にでも公開できるような情報のみとし、センシティブな情報はゼッタイ入れない)


公開しているWeb APIを更新する

公開>Webアプリケーションとして導入 を選択していまつくったJSONP対応コードに更新する。



image.png


新しいバージョンを公開したいときは、プロジェクトバージョンを新規作成する。
変更内容は入力しなくてもよい。

さっきのが バージョン1 だったので、次は自動的に 2 になる。


HTMLをつくって、ブラウザからアクセスする

以下のような htmlファイルを作る。

今回は、JSONPへのアクセス用にjQueryを使った。

index.html
<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>GAS Client Example</title> 
</head> 
<body> 
<script src="https://code.jquery.com/jquery-3.3.1.min.js" 
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" 
        crossorigin="anonymous"></script> 
<script> 
    const endpoint = "https://script.google.com/macros/s/xxxxxxxxxx/exec"; 
    $.ajax({ 
        type: 'GET', 
        url: endpoint, 
        dataType: 'jsonp', 
        data: { 
            text: 'Hi,There!' 
        }, 
        success: out => { 
            alert(out.message); 
        } 
    }); 
</script> 
</body> 
</html> 
const endpoint = "https://script.google.com/macros/s/xxxxxxxxxx/exec"; 
この部分には、さきほどの 公開>Webアプリケーションとして導入で確認できる現在のWebアプリケーションのURLを入力する。



image.png


さて、いまつくった index.html をブラウザで開いてみる。

ローカルファイルでも開ける。



image.png


うまく呼び出すことができた。

これで、シンプルなWeb APIがお手軽に作れた。


デバッグ、テストの方法

デバッグの方法はいろいろあるがいちばん準備が少なくて良いのは、デフォルトで準備されているスクリプトエディタとなる。


スクリプトエディタ上で実行する

ブラウザ上から編集できるスクリプトエディタには、スクリプトの実行機能やデバッグ機能がついているので実行してみる

ここでは、doGetを呼び出すために以下のようなコードを main.gs に追加した。

main.gsへの追加分
function testLogic() { 
    var e = 
        { 
            "parameter": { 
                "text": "hello", 
                "callback": "myCallbackFunc" 
            } 
        }; 
    var out = doGet(e); 
    var content = out.getContent(); 
    Logger.log("content=" + content); 
} 
#doGetのロジックがちゃんと動作しているのか、この#testLogic関数をつかって確かめてみる。

以下のように実行したい関数を選択できるので、 testLogicを選択して、



image.png


実行ボタンimage.pngをクリックすると実行される。

表示>ログでログ画面を表示することができるので、



image.png


ログ画面を表示してみた。



image.png


ちゃんと動作している模様。


デバッグ機能を使う

今のはふつうに実行だったが、今度はデバッグ機能image.pngをつかう。

デバッグ実行するまえに、プログラムの実行を一時停止するブレークポイントを設定する。

コードの行番号のところを、マウスでポチっとすると、赤丸●がついて、ここにブレークポイントがセットされる。



image.png


この状態でimage.pngをクリックする

すると、以下のような感じで、ブレークポイントまで実行され、ウォッチ画面が表示される。



image.png


一時停止や再開、ステップ実行などひととおりの機能がブラウザベースでできるので、なかなか便利。


Google Apps Scriptから自分自身を呼び出す

main.gsに以下を追加する。

main.gs追加分
function testGet() { 
 
    var url = ScriptApp.getService().getUrl() + "?text=Hello&callback=myFunc001"; 
    Logger.log("url=" + url); 
 
    var options = { 
        "method": "GET", 
        "followRedirects": true, 
    }; 
 
    var response = UrlFetchApp.fetch(url, options); 
    Logger.log("response=" + response); 
} 
このコードは、自分自身を呼び出してみる関数になっている。

var url=ScriptApp.getService().getUrl() ・・・ 
ScriptApp.getService().getUrl()で自分自身のURLを取得する

var options = { 
        "method": "GET", 
        "followRedirects": true, 
    }; 
    var response = UrlFetchApp.fetch(url, options); 
こちらは、実際に GETメソッドで外部サービス(といっても自分自身)を呼び出しにいっている。外部サービスに接続にいくときは、 UrlFetchAppを使う。

ここまでのコード(main.gs)は以下のようになっている。

main.gs
//HTTP GETをハンドリングする 
function doGet(e) { 
 
    //リクエストパラメータ名"text"の値を取得する 
    var text = e.parameter.text; 
 
    var value; 
 
    if (text) { 
        value = "You say " + text; 
    } else { 
        value = "Please say something!"; 
    } 
 
    var result = { 
        message: value 
    } 
 
    var responseText; 
 
    var out = ContentService.createTextOutput(); 
 
    var callback = e.parameter.callback; 
 
    if (callback) { 
        responseText = callback + "(" + JSON.stringify(result) + ")"; 
        //Mime Typeをapplication/javascriptに設定 
        out.setMimeType(ContentService.MimeType.JAVASCRIPT); 
 
    } else { 
        responseText = JSON.stringify(result); 
        //Mime Typeをapplication/jsonに設定 
        out.setMimeType(ContentService.MimeType.JSON); 
    } 
 
 
    //JSONPテキストをセットする 
    out.setContent(responseText); 
 
    return out; 
} 
 
function testLogic() { 
    var e = { 
        "parameter": { 
            "text": "hello", 
            "callback": "myCallbackFunc" 
        } 
    }; 
    var out = doGet(e); 
    var content = out.getContent(); 
    Logger.log("content=" + content); 
} 
 
function testGet() { 
 
    var url = ScriptApp.getService().getUrl() + "?text=Hello&callback=myFunc001"; 
    Logger.log("url=" + url); 
 
    var options = { 
        "method": "GET", 
        "followRedirects": true, 
    }; 
 
    var response = UrlFetchApp.fetch(url, options); 
    Logger.log("response=" + response); 
} 
さて、実行対象関数を testGetに指定して、


image.png


実行image.pngしてみると、こんなダイアログがでてきた。



image.png


許可を確認をクリックすると、



image.png


認可画面がでてくるので、内容確認して 許可をクリック。

実行が終わった後に、ログ画面を表示してみると、きちんと動作していた。



image.png


ここまででひとまず基本的な使い方は理解できた。


ローカルで開発したい、Gitでコード管理したい、クラスを使いたい、TypeScriptを使いたい、などの要求(欲求)とやり方

Google Apps Scriptにも効率化やモダン?な開発を促進するための各種ソリューションを先人たちが親切にも準備してくれているのでキーワードだけカンタンに整理しておく。


ローカルで開発したい!

要求:ブラウザ上のエディタじゃものたりません、ローカルで開発したいです

  • そんなときは、ローカルでの開発を助けてくれるclasp。GITに似たコマンド体系で操作できる。
インストール

npm i @google/clasp -g 
インストールしたらログインする。Googleのアカウントで入る。

clasp login 
ローカルにプロジェクトを落としてくる

clasp clone [scriptId/scriptURL] 
clasp clone "15ImUCpyi1Jsd8yF8Z6wey_7cw793CymWTLxOqwMka3P1CzE5hQun6qiC" 
clasp clone "https://script.google.com/d/15ImUCpyi1Jsd8yF8Z6wey_7cw793CymWTLxOqwMka3P1CzE5hQun6qiC/edit" 
pullする。バージョン指定も可能。

clasp pull 
clasp pull -versionNumber 2 
pushする。

clasp push 
claspでローカルに落としてきたものをGitHubで管理したりできそう。


GitHubでコード管理したい!

要求:Google Apps ScriptのコードはGoogle Driveに保存されるが、あっぱりGitHub使いたい!

chrome拡張として提供されている。

前節でふれたclaspをつかってローカル→GitHubでもいいし、chrome拡張つかってもよさそう。


クラスを使って書きたい!

要求:クラスを使いたい!

  • そんなときは、まずES5のprototypeをつかったクラス風で満足できないか?
ES5時代のクラス風構文
function Greeting(timing) { 
    this.timing = timing; 
} 
 
Greeting.prototype.sayHello = function (name) { 
    if (!name) { 
        name = "Man"; 
    } 
    if (this.timing == 'morning') { 
        return 'Good morning,' + name; 
    } else { 
        return 'Hello,' + name; 
    } 
}; 
 
 
function doGet(e) { 
 
    var g = new Greeting("morning"); 
    var hello = g.sayHello("John"); 
 
    var result = { 
        message: hello 
    }; 
 
    var responseText = JSON.stringify(result); 
    var out = ContentService.createTextOutput(); 
    out.setMimeType(ContentService.MimeType.JAVASCRIPT); 
    out.setContent(responseText); 
 
    return out; 
} 
要求:ES5のクラス風とかではなく、TypeScriptを使ってきちんと書きたい


ユニットテストがしたい

要求:Google Apps Scriptでもユニットテストがしたい


まとめ

  • Google Apps Script(GAS)でWeb APIを公開する方法をハンズオン的にみてきました
  • 今回はほんの触りだけでしたが、機能豊富で味わい深い使い方ができそうです

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)