見出し画像

#117 API のデフォルト値が変わっているようです

 意味不明な記事タイトルかもしれませんが、GAS(Google Apps Script)から呼び出している API のデフォルト値が変更になっているようです。


はじめに

過去の記事に寄せられた以下のようなコメントが寄せられました。

クラスIDの取得→そのクラスに所属している生徒のアドレスを取得→ストリームに個人あてのメッセージを投稿、
という流れのスプレッドシートを作成してみたのですが、生徒のアドレスを取得しようとすると、なぜか3行目から32行目までの30人分のアドレスしか取得されません。(生徒が30人より多いのにもかかわらず)
GASの知識が足りず、どのようにすれば32行目で止まることなく、生徒のアドレスを取得できるのか分からず、新年度を前に非常に困っています。

このコメントから、何が原因なのか気になったので、状況の確認を行ってみました。

どういうこと?

具体的には、以下のように Classroom のクラスに参加している生徒の一覧を取得する courses.students.list などで指定できるパラメータ pageSize のデフォルト値が変わっているようです。

下図のように「指定しない場合のデフォルトは 30、または 0 です。」となっていますが、以前はこの部分が 0 がデフォルト値になっていて、読み込めるだけ読み込んでくれていたように記憶しています。
しかしながら、現在は 30 が適用されているケースがあるようです。

パラメータの詳細(courses.students.list)

対策

冒頭のコメントのような状況になった場合、次のような対策が考えられます。

  1. API を呼び出すときには pageSize を意図したサイズで指定する。

  2. API を呼び出すときには pageToken を用いて、継続して読み込む。

前者 1. だけで対応できるケースもあるかもしれませんが、確実に対処するのであれば、後者 2. も含めて行うべきです。 というか、2. の対策が講じられていれば、1. の pageSize を指定していなくても、くり返し読み込み、すべてのデータを処理してくれます。

実際に 2. の対策を行ったプログラムを作成してみました。
以下の URL にアクセスすることで、自身の Google ドライブにスプレッドシートをコピーできます。

https://docs.google.com/spreadsheets/d/1DV1o3VhpsC3EmY-3Px9_2ZfSjsUlMX3VCuAppljYky8/template/preview

'use strict'

/**
 * 追加のメニュー項目を設定する
 */
function onOpen() {
  let ui = SpreadsheetApp.getUi();
  ui.createMenu('Classroom API のサンプル')
    .addItem('処理実行', 'classMemberOutput')
    .addToUi();
}

/**
 * Classroom API の動作確認
 */
function classMemberOutput() {
  let sheet = SpreadsheetApp.getActiveSheet();
  let courceId = Browser.inputBox("処理対象のクラスの ID を入力してください。", Browser.Buttons.OK_CANCEL);
  if (courceId == 'cancel') {             // クラスの ID 入力がキャンセルされた。
    return;                               // → 処理を終了
  }

  let pageToken = null;
  do {
    // 
    let res = Classroom.Courses.Students.list(
      courceId,
      {
//      'pageSize': 30,
        'pageToken': pageToken,           // 前の list 呼び出しから返された nextPageToken 値。
      }
    );

    for (let i = 0 ; i < res.students.length ; i++) {
      sheet.appendRow(
        [
          res.students[i].profile.name.familyName,
          res.students[i].profile.name.givenName,
          res.students[i].profile.emailAddress,
        ]
      );
    }
    pageToken = res.nextPageToken;
  } while (pageToken != null);
}

このプログラムは、追加されたメニューから「Classroom API のサンプル」→「処理実行」と選択することで、下図のようにクラスの ID を入力するダイアログが表示されます。

クラスの ID を入力するダイアログ

このダイアログで、処理対象となるクラスの ID を入力すると、入力されたクラスに「生徒」として参加しているユーザーの

  • メールアドレス

をシートに書き出すものです。ただ書き出しているだけで、それ以上の意味はありません。

なお、スクリプトの初回実行時には、実行するアカウントによる確認作業が必要になります。詳しくは以下の投稿をご覧ください。

プログラムの解説

23~44行目が実際に処理している部分ですが、変数 pageToken に API から得られた nextPageToken を指定し、その値が null(厳密には undefined)になるまで do ~ while でくり返しています。

作成した動作確認のためのプログラム

30行目の pageToken に、2回目以降の API 呼び出しでは、前回の呼び出しで得られた nextPageToken を指定することで、前回の続きから読みだしています。

29行目ではコメントアウトしてありますが、実際には 30が指定されているのと同じ動作をしています。あたかもデフォルト値が 30 に設定されているような挙動です。

以前に pageSize に 100 と指定しても、それよりも小さな件数しか読み込まないケースを見たことがあります。そのため、前述の 1. のように十分な pageSize を指定しておくだけでは、意図しない動作になってしまうケースがあるかもしれません。
そのため、2. の対策を行っておくことが重要だと思います。

最後に

今回のプログラムは、冒頭のように寄せられたコメントからはじまっています。日本の感覚では、pageSize のデフォルト値は 30 では心もとない感じしてしまいます。一般にクラスの人数は 40 もしくは 35 なので…
海外の学校では、クラスの人数が 30 以下なのかもしれませんね。😖
コメントを寄せられた方と同様に、pageToken を利用せずに、一回の読み込みだけで処理させようとしていた場合、うまく動作しない場合があるかもしれないので、そのような場合は ↑ のサンプルのようにくり返し読み込むように変更しましょう。

最後に、お決まりのフレーズなどを書いておきます。

  • 一応の動作確認は行っているものの、不慮のトラブルによって損害等が生じても、責任はとれませんので予めご了承ください。

  • コメントを含めても 45行程度のスクリプトであり、実行に際して目的外の場所への書き出しや収集などは行っていません。

  • 特別なエラー処理は行っていないので、意図しないケースでエラーが発生してしまうかもしれません。どうにもならない場合には、ご連絡ください。

わたし自身にしてみると、このような「スクリプトを作ること」が目的になっているような感じですが、このスクリプトが何かの役に立てば幸いです。
「スキ ♡」を押してもらえると、このようなプログラム作成の励みになります。😍

この記事が気に入ったらサポートをしてみませんか?