slackユーザーデータをJSONファイルとしてGoogleドライブに保存する
前回の記事の続きです。
前回:
GASを使ってslackユーザーデータを取得する(1000件以上対応) - シンプルに暮らしたい情シスのブログ
次回:
今回はAPIリクエストの結果(ユーザーデータ)をJSONファイルとしてGoogleドライブに保存するGASを作っていきます。
JSONファイルとして保存するメリット
リクエスト回数の節約
APIには「1時間に〇回まで」や、「1分間に〇回まで」といった制限が設けられていることが多いです。
今回使ったslack API(users.list)の場合、Rate limitsを見ると Tier2となっています。
Tier2のところをクリックすると、飛べるRate Limitsの解説ページではこのように記載があり、どうやら1分間に20回程度は行えるようです。
1000件を超えるユーザー数の場合は、1度の取得で2回以上のリクエストを行うため、実行回数によってはオーバーしてしまう可能性があります。
そこで1日に1回更新する程度で良いようなデータは、JSONファイルとして保存し、users.list APIを使う代わりにJSONファイルを読み込めば、APIの実行制限を超えるようなケースは避けられます。
事前準備
コード
JSONファイルを作成するコード
まずは単純にJSONファイルを作成するコードです。
新規作成と既存ファイルの更新ではそれぞれ処理が異なるため、別々に書いていきます。
function createJson() { // スクリプトプロパティに設定したfolder_idを呼び出す const folder_id = PropertiesService.getScriptProperties().getProperty("folder_id"); // ユーザーデータ(仮) const users_data = [ { "name": "hogehoge" }, { "name": "hagehage" } ]; // 保存先のフォルダー情報を取得 const folder = DriveApp.getFolderById(folder_id); // Blobオブジェクトを作成 const content_type = "application/json"; const file_name = "users_list_response.json"; const blob = Utilities.newBlob("", content_type, file_name); blob.setDataFromString(JSON.stringify(users_data),"UTF-8"); // Blobオブジェクトにデータをセット // Blobオブジェクトをファイル化し、保存先フォルダーへ保存 folder.createFile(blob); }
これを実行すると、JSONファイルが作成されました。
中身を見てみると、
[{"name":"hogehoge"},{"name":"hagehage"}]
がちゃんと入っています。
ちなみに
blob.setDataFromString(JSON.stringify(users_data),"UTF-8");
この部分でusers_dataをJSON.stringifyで囲っていますが、これをしない場合(データがJSONオブジェクトの場合)このようになってしまいます。
JSONファイルを更新するコード
先ほど作成したファイルのIDを取得します。
リンクをコピー
取得したリンクの赤線部分がファイルIDです。
後ほどファイルIDを自動的に取得する処理を設けるので、
ここでははスクリプトプロパティには入れず、コード内に直接記載します。
function updateJson() { // 更新対象のファイルID const file_id = "xxxxxxxxxxxxxxxxxxxxxxxx"; // 更新対象ファイルを取得 const file = DriveApp.getFileById(file_id); // 更新するユーザーデータ(仮) const users_data = [ { "name": "sato" }, { "name": "suzuki" } ]; // 更新対象ファイルへデータを上書きする file.setContent(JSON.stringify(users_data)); }
これを実行すると、先ほどのjsonファイルの中身が更新されました。
createJsonとupdateJsonの2つのコードで運用する場合、
- 初回はcreateJsonを実行
- 2回目以降はfile_idを設定し、updateJsonを実行
というちょっとイケてない運用になります。
1つのコードで作成・更新をしたいので、
- フォルダ内から指定の特定のファイル名のファイルを探す
- 無ければ作成
- あれば更新
という処理にしたいです。
保存先フォルダ内からファイルを探してIDを取得するコード
まずは保存先のフォルダから、特定のファイル名のファイルを探し、IDを取得します。
function searchFileId() { // スクリプトプロパティに設定したfolder_idを呼び出す const folder_id = PropertiesService.getScriptProperties().getProperty("folder_id"); // 保存先のフォルダー情報を取得 const folder = DriveApp.getFolderById(folder_id); // フォルダー内のファイル一覧を取得 const files = folder.getFiles(); // 探したいファイル名 const file_name = "users_list_response.json"; // ファイルIDを格納する変数 let file_id; // ファイル一覧から1件ずつ探す while (files.hasNext()) { const file = files.next(); // ファイルが見つかった時の処理 if (file.getName() == file_name) { file_id = file.getId(); break; // ファイルが見つかった時点でループ終了 } } Logger.log(file_id); }
実行すると上手く取得できました。
ファイルが見つからない場合はfile_idがnullになります。(変数宣言時の値になる)
JSONファイルの作成・更新を一括で行うコード
上記3つのコードを組み合わせて、作成・更新を1つのコードにまとめます。
良い関数名が思い浮かばなかったのでChatGPTに考えてもらいました。
(ちなみにcreateUpdateJsonあたりにしようと思ってました)
折角なので作った関数を少し変えて、引数を渡すことで同じ記述を避けるように改修します。
function createOrUpdateJson() { // スクリプトプロパティに設定したfolder_idを呼び出す const folder_id = PropertiesService.getScriptProperties().getProperty("folder_id"); // 検索や作成に使うファイル名 const file_name = "users_list_response.json"; // ユーザーデータ(仮) const users_data = [ { "name": "hogehoge" }, { "name": "hagehage" } ]; // フォルダ内にある対象のJSONファイルのIDを取得する const file_id = searchFileId(folder_id, file_name); if (file_id == null) { createJson(folder_id, file_name, users_data); Logger.log("ファイルが存在しないため作成"); } else { updateJson(file_id, users_data); Logger.log("ファイルが存在するため更新"); } } function createJson(folder_id, file_name, users_data) { // 保存先のフォルダー情報を取得します const folder = DriveApp.getFolderById(folder_id); // Blobオブジェクトを作成 const content_type = "application/json"; const blob = Utilities.newBlob("", content_type, file_name); blob.setDataFromString(JSON.stringify(users_data), "UTF-8"); // Blobオブジェクトにデータをセット // Blobオブジェクトをファイル化し、保存先フォルダーへ保存 folder.createFile(blob); } function updateJson(file_id,users_data) { // 更新対象ファイルを取得 const file = DriveApp.getFileById(file_id); // 更新対象ファイルへデータを上書きする file.setContent(JSON.stringify(users_data)); } function searchFileId(folder_id, file_name) { // 保存先のフォルダー情報を取得 const folder = DriveApp.getFolderById(folder_id); // フォルダー内のファイル一覧を取得 const files = folder.getFiles(); // ファイルIDを格納する変数 let file_id; // ファイル一覧から1件ずつ探す while (files.hasNext()) { const file = files.next(); // ファイルが見つかった時の処理 if (file.getName() == file_name) { file_id = file.getId(); break; // ファイルが見つかった時点でループ終了 } } return file_id; }
一度フォルダ内を空にし、createOrUpdateJsonを実行してみます。
対象のファイルが無いのでcreateJsonが実行されていますね。
続いて2回目の実行
今度はファイルが存在しているので、上手くupdateJsonが実行されています。
slackユーザーデータをJSONファイルとしてGoogleドライブに保存するコード(全体)
前回作ったコードと組み合わせて、
- slackユーザーデータの取得
- JSONファイルの作成or保存
を一括で行う形にします。
createOrUpdateJsonにusers_dataを引数で渡す形にして使いまわします。
function Main() { let cursor = ""; let users_data = []; // slackAPIは1度で1000件までしか取得できないので、1000件を超える場合(next_cursorに値がある場合)繰り返す do { let response = callUsersList(cursor); cursor = response["response_metadata"]["next_cursor"]; // こちらの説明は後述 users_data.push(...response["members"]); // こちらの説明は後述 test(response); } while (cursor != ""); // next_cursorに値が無い場合=全て取得し終わった場合、ループを終了する createOrUpdateJson(users_data); } function callUsersList(cursor) { // スクリプトプロパティに設定したbot_tokenを呼び出す const token = PropertiesService.getScriptProperties().getProperty("bot_token") const url = "https://slack.com/api/users.list" //APIのURL // payloadを設定 const payload = { "token": token, "cursor": cursor } // optionsを設定 const options = { "method": "GET", "payload": payload, "headers": { "contentType": "x-www-form-urlencoded", } } // APIリクエストの結果をresponseに格納 const response = UrlFetchApp.fetch(url, options); // responseの文字列をJSON解析しオブジェクト化して返す return JSON.parse(response); } function createOrUpdateJson(users_data) { // スクリプトプロパティに設定したfolder_idを呼び出す const folder_id = PropertiesService.getScriptProperties().getProperty("folder_id"); // 検索や作成に使うファイル名 const file_name = "users_list_response.json"; // フォルダ内にある対象のJSONファイルのIDを取得する const file_id = searchFileId(folder_id, file_name); if (file_id == null) { createJson(folder_id, file_name, users_data); } else { updateJson(file_id, users_data); } } function createJson(folder_id, file_name, users_data) { // 保存先のフォルダー情報を取得します const folder = DriveApp.getFolderById(folder_id); // Blobオブジェクトを作成 const content_type = "application/json"; const blob = Utilities.newBlob("", content_type, file_name); blob.setDataFromString(JSON.stringify(users_data), "UTF-8"); // Blobオブジェクトにデータをセット // Blobオブジェクトをファイル化し、保存先フォルダーへ保存 folder.createFile(blob); } function updateJson(file_id,users_data) { // 更新対象ファイルを取得 const file = DriveApp.getFileById(file_id); // 更新対象ファイルへデータを上書きする file.setContent(JSON.stringify(users_data)); } function searchFileId(folder_id, file_name) { // 保存先のフォルダー情報を取得 const folder = DriveApp.getFolderById(folder_id); // フォルダー内のファイル一覧を取得 const files = folder.getFiles(); // ファイルIDを格納する変数 let file_id; // ファイル一覧から1件ずつ探す while (files.hasNext()) { const file = files.next(); // ファイルが見つかった時の処理 if (file.getName() == file_name) { file_id = file.getId(); break; // ファイルが見つかった時点でループ終了 } } return file_id; }
Mainを実行すると、作成・更新されたJSONの中身が、前回の実行結果と同じになりました!
このMainを時間トリガーで実行することで、最新のユーザーデータ(JSON)を更新し続けることができます。
おまけ(トリガー設定)
時間実行トリガーの設定方法です。
GASの左メニューの時計アイコンをクリック
トリガーを追加
設定項目 | 内容 |
---|---|
実行する関数を選択 | Main |
イベントのソースを選択 | 時間主導型 |
時間ベースのトリガーのタイプを選択 | お好み |
時間の間隔を選択(時間) | お好み |
上記の設定をして保存します。
このスクショの設定の場合は6時間ごとに実行されます。
※トリガー設定時の注意
トリガーは、トリガーを作成したアカウントに依存します。
作成したアカウントが退職などで削除された場合、実行されなくなるため、削除の可能性が無いアカウントでトリガーを作成することを推奨します。
まとめ
今回のコードでユーザーデータをJSONファイルで保存することができました。
次回は保存したJSONファイルを読み込み、活用するやり方をご紹介します。
前回:
GASを使ってslackユーザーデータを取得する(1000件以上対応) - シンプルに暮らしたい情シスのブログ
次回: