【GAS】WebアプリやAPIも作れちゃう!HtmlService、ContentServiceについて、できることをまとめてみた。 ~ その④ JSON API ~

HtmlService、ContentServiceまとめシリーズ

HtmlServiceでAPI作れちゃうとか書きましたが、思いっきり訂正させてください。筆者がGASでAPIを作るときによく使うのは、「ContentService」でした。申し訳ありません。タイトルもその④から思いっきり訂正しています。

ということで、気を取り直して、GASでJSONを返すAPIを作ってみたいと思います。

基本形

今までは、URLにアクセスがあった場合に、doGet関数の処理が起動し、HTMLをレスポンスとして返すということをしていました。

ここではURLにアクセスがあった場合にJSONをレスポンスで返すということをしてみたいと思います。

具体的には以下のようなコードになります。


コード.gs

function doGet(e) {
  var json = {
    hoge: 'fuga',
    hogehoge: 'fugafuga'
  };
  
  var res = ContentService.createTextOutput();
  res = res.setMimeType(ContentService.MimeType.JAVASCRIPT);
  res = res.setContent(JSON.stringify(json));
  
  return res
}

その① Webアプリケーションの基本で書いたように、Webアプリケーションの導入を行い、ブラウザでアクセスしてみると、以下のようにJSONのレスポンスが返ってくることがわかります。

POSTリクエストの処理

ブラウザでURLを入力し、リクエストする場合はGETリクエストとなります。GETリクエスト時にはdoGet関数が起動し、レスポンスを返していました。

POSTリクエストは処理できないのでしょうか?いえいえ、そんなことはありません。GASにはPOSTリクエストに対応するdoPost関数があります。

次は、doPost関数でレスポンスを返す処理を書いてみましょう。具体的には先ほどと同じように記述してみます。


コード.gs

function doPost(e) {
  var json = {
    hoge: 'fuga',
    hogehoge: 'fugafuga'
  };
  
  var res = ContentService.createTextOutput();
  res = res.setMimeType(ContentService.MimeType.JAVASCRIPT);
  res = res.setContent(JSON.stringify(json));
  
  return res
}

このdoPost関数の動きをチェックするためには、POSTリクエストを発行しなければいけません。チェックするのにもGASを使ってPOSTリクエストを発行してみましょう。
具体的には以下のようなコードで、POSTリクエストを送信することができます。


コード.gs

function postTest() {
  var url = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec";
  
  var params = {
    method: "POST"
  }
  var fetch = UrlFetchApp.fetch(url, params);
  Logger.log(fetch.getContentText());
}

また、チェックする前に、Webアプリケーションにアクセスできるユーザーを誰でもアクセスできるようにしておきましょう。POSTリクエストには認証情報は何も付加されていないので、エラーとなります。

実際にPOSTリクエストを発行すると、ログに以下のようなレスポンスが記録されています。

リクエストパラメーターの取得

doGet、doPostでは、リクエストパラメーターを取得できます。リクエストパラメーターというのは、GETリクエストでいうところのhttp://example.com?item1=hoge&item2=fugaの部分ですね。

doGetを例にすると、以下のように記述できます。とても簡単ですね。


コード.gs

function doGet(e) {
  var json = {};
  
  // リクエストパラメーターの取得
  json.item1 = e.parameter.item1;
  json.item2 = e.parameter.item2;
  
  var res = ContentService.createTextOutput();
  res = res.setMimeType(ContentService.MimeType.JAVASCRIPT);
  res = res.setContent(JSON.stringify(json));
  
  return res
}

e.parameter.[parameterの名前]で取得できちゃいます。とても簡単ですね。これについては、POSTでも同様に取得できます。
これで例えば上記のようにGETリクエストをブラウザにて送信すると、以下のように、パラメーターによってレスポンスが変化していることがわかります。

doGet、doPost内で処理を分岐させたいときなんかに便利です。

JSONP

こうなってくると、ブラウザのJavaScriptからAjaxでデータを取得したいという欲求も出てくるかと思いますが、やはりクロスドメインの問題が発生します。
それを回避するための方法として、JSONPという手法があります。
これにより、GASにブラウザからリクエストを送信し、JSONのレスポンスを受け取って、ブラウザで処理をする、といったことが可能となります。

GAS側のコード

それでは、実際にやってみましょう。まずはGAS側に以下のコードを記載します。


コード.gs

function doGet(e) {
  var json = {};
  json.item1 = e.parameter.item1;
  json.item2 = e.parameter.item2;

  var callback = e.parameter.callback;
  
  var res = ContentService.createTextOutput(callback + '(' + JSON.stringify(json) + ')');
  res = res.setMimeType(ContentService.MimeType.JAVASCRIPT);
  
  return res
}

ポイントとしては、createTextOutputしているところで、関数の文字列を作っているところです。
このプロジェクトをWebアプリケーションとして公開し、URLをメモしておきます。

ブラウザ側のコード

それではブラウザ側でこのdoGet関数を叩いてJSONを取得してみようと思います。まずは説明する前にブラウザ側のコードを見ていただければと思います。


index.html

<!DOCTYPE html>
<html>
  <head>
    <title>JSONPテスト</title>
  </head>
  <body>
    <div id="response"></div>
    <script>
    function myCallback(json) {
      document.getElementById('response').innerHTML = JSON.stringify(json);
    }
    </script>
    
    <!-- 先ほどメモしたURLをsrcに挿入 -->
    <script src="https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxscript-id/exec?item1=hoge&item2=fuga&callback=myCallback"></script>
  </body>
</html>

お分りいただけますでしょうか?
先ほどメモしたURLをscriptタグに挿入しています。こうすることで、GAS側で生成した関数の文字列をブラウザ側で実行するような処理がなされます。
srcに挿入したURLのパラメーターに「myCallback」としていますので、このscriptタグを処理すると、ブラウザ側にてjsonが引数となるmyCallback関数が実行されます。
ブラウザに、JSONの文字列が表示されれば成功です。

まとめ

いかがでしたでしょうか?ちょっと上級テクニックな感じもしますが、GASの可能性が広がれば幸いです。