【GAS】スプレッドシートを用いたAPI作成の基本

プログラミング初心者の勉強ブログ #120

GAS(Google Apps Script)を使ったAPI作成の基本についてのまとめ。「APIを作る」と言うとハードルが高そうだが、GASのサービスを使ってGoogleのapp群をJSで動かし、自分のアプリが欲しいデータを返すようにコードを少し書くだけ。「あらかじめGoogleが用意しているAPIを自分オリジナルに設定し外部に公開できる」みたいな感じ。

 

目次

[toc]

 

Google Apps Script

gas

https://developers.google.com/apps-script/

 

GASはスプレッドシートやドキュメント、Gmail、Google MapなどのGoogleが提供するサービスを、自分が書いたJavaScriptで制御することができる仕組みを提供しており、これを使うことでGoogleのサービスをAPIとして自分のアプリで活用できるようになる。使い方は様々あると思うが、今回はGoogleスプレッドシートをDB的に活用してみる。ちなみに料金は無料であり、一方で利用制限があり従量課金制は無い。

 

スプレッドシートに記入した内容をレスポンスとして返すAPIを公開する

とりあえず試しに使ってみる。今回はスプレッドシートと連携したのでその流れを書いていく。

 

G Suite Developer Hub

G Suite Developer Hub

https://script.google.com/home

 

上のリンクよりG Suite Developer Hubに入る。ここで自分のプロジェクトを管理できる。

 

新規プロダクト作成

 

左上の「新規スクリプト」をクリックすると、以下のような画面が開く。

ファイル → 新規作成 → スプレッドシートを選択していく。

 

スプレッドシートを選択

 

スプレッドシートが開くので書き込んでタイトルつけて保存する。今回は免許の問題をとりあえずコピペした。

 

スプレッドシートを記入

上の内容についてだが、列を左からみて、

ジャンルID / 問題文 / 正誤 / 解説

のような形で入力してある。

 

入力したら、最初のスクリプト入力の画面に戻るために、

ツール → スクリプトエディタ

をクリックする。

 

スクリプトを表示

 

ここからが本番。スクリプトを以下のように書いていく。

 

スクリプトを書く

コードを分けてみていく。

// 紐付けたスプレッドシートを取得しsheetに格納
var sheet = SpreadsheetApp.getActiveSheet();

// ランダム関数で問題(810問)の中から1つを選択するためのindex番号を設定
var rowIndex = Math.ceil(Math.random() * 810);

// qに問題、aに解答、sに解説を格納する
// sheetに対しgetRange(row, col)でセルを指定、getValue()で取得
var colStartIndex = 2;
var q = sheet.getRange(rowIndex, colStartIndex).getValue();
var a = sheet.getRange(rowIndex, colStartIndex+1).getValue();
var s = sheet.getRange(rowIndex, colStartIndex+2).getValue();

ここまでの流れで、sheetからセルを選択してその値を格納している。

// JSONの型でさっきのq、a、sをまとめる
var json = [];
var result = {
  q: q,
  a: a,
  s: s
}
json.push(result);

// CORBを抜けるためにJSONPなるものに型を変える。
// ここら辺は理解が曖昧、とりあえずこれでAPIとして機能した。
var jsonp = "apicallback(" + JSON.stringify(json) + ")";

// レスポンスで返すために返り値を指定する
// setMimeType()でレスポンスのMimeTypeをセットしておく
var out = ContentService.createTextOutput(jsonp); 
out.setMimeType(ContentService.MimeType.JAVASCRIPT);
return out;

 

あとは公開するために少しだけ設定を行う。

公開 → ウェブアプリケーションとして導入…

をクリックする。

 

公開準備1

※画像によってタイトルが違うが、後からスクショを追加でとっただけなので無視して欲しい。紛らわしくて申し訳ありません。

以下のようなモーダルが出てくる。

公開準備2

 

適当にバージョン名を入力し、アプリケーションにアクセスできるユーザーを「全員(匿名ユーザーを含む)」に指定。

導入を押すと、

 

公開準備3

公開の設定が完了する。「現在のウェブアプリケーションのURL」を叩くことで、指定した返り値を自分のアプリで取得できるようになる。

 

自分のアプリでAPIにリクエストを送る

今回コードはかなりテキトーなので汚いが、とりあえず自分のアプリで公開したAPIにリクエストを送るためのコードを載せる。

 

スクリプト抜粋

// 公開したAPIのURL
const url = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec";

// APIにリクエストを送る関数
const setAjax = url => {
  $.ajax({
    type: "GET",
    url: url,
    dataType: 'jsonp',
    contentType: 'application/javascript',
    // apicallbackはAPI側の返り値で設定したときの関数名
    jsonpCallback: 'apicallback',
  })
  .then(data => {
    // 取得成功時の実行内容
    setQuestion(data[0]);
  })
  .catch(() => {
    // 失敗時
    alert("取得失敗");
  });
};

setAjax(url);

 

 

実際のコード

APIで取得した問題(今回はランダム)を連続して出題できるような実装。

 

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
      integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay"
      crossorigin="anonymous">
<link rel="stylesheet" href="css/sample.css">
<title>免許問題</title>
</head>
<body>
<header>
  <h1>免許問題</h1>
  <span id="count"></span>
</header>
<main>
  <p id="quest">Loading...</p>
  <div class="btnWrap">
    <div value="true" class="btn"><i class="far fa-circle"></i></div>
    <div value="false" class="btn"><i class="fas fa-times"></i></div>
  </div>
  <div id="explanation" style="display: none;"></div>
</main>
<footer></footer>

<script>
  let q;
  let a;
  let s;
  let counter = 0;
  let trueCounter = 0;

  // 公開したAPIのURL
  const url = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec";
  const setQuestion = json => {
    q = json["q"];
    a = json["a"];
    s = json["s"] === "" ? 'この問題の解説はありません。' : json["s"];
  };
  const setHTML = () => {
    $('#quest').html(q);
    $('#explanation').html(s);
    $('#count').html(counter + '問中' + trueCounter + '門正解');
  };
  const setEvent = () => {
    $(".btn").on('click', function(e) {
      const val = e.currentTarget.getAttribute('value');
      if (val === String(a)) {
        alert('正解!');
        trueCounter++;
      } else {
        alert('不正解');
      }
      $(".btnWrap").css("display", "none");
      $('#explanation').fadeIn();
      $('main').append('<div id="next">次へ</div>');
      $("#next").on('click', function() {
        $('#quest').html("Loading...");
        $('#explanation').css("display", "none");
        $(".btnWrap").css("display", "block");
        $(this).remove();
        setAjax(url);
      });
    });
  };

  // APIにリクエストを送る関数
  const setAjax = url => {
    $.ajax({
      type: "GET",
      url: url,
      dataType: 'jsonp',
      contentType: 'application/javascript',
      jsonpCallback: 'apicallback',
    })
    .then(data => {
      setQuestion(data[0]);
      setHTML();
      counter++;
    })
    .catch(() => {
      alert("取得失敗");
    });
  };

  setAjax(url);
  setEvent();
</script>
</body>
</html>

 

まとめ

APIとか通信は意外と面白い。

以上ありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA