HTTPリクエストしたい(UrlFetchApp

1UrlFetchApp.fetch("URL", "オプション");

UrlFetchApp.fetchで指定したURLに対してHTTPリクエスト(GETPOSTなど)できます。 コンテンツタイプやHTTPヘッダーなどはオプションできます。

GETリクエストしたい

 1function fetchData() {
 2    // URLを指定する
 3    const url = "https://httpbin.org/get";
 4
 5    // GETリクエストを送信する
 6    const response = UrlFetchApp.fetch(url);
 7
 8    // レスポンスの内容を取得する
 9    const content = response.getContentText();
10    Logger.log(`content: ${content}`)
11}

指定したURLに対してGETリクエストを送信し、レスポンスを取得するサンプルです。

POSTリクエストしたい

 1function postData() {
 2    // URLを指定する
 3    const url = "https://httpbin.org/post";
 4    // オプションを設定する
 5    const options = {
 6        "method": "post",
 7        "payload": {
 8            "key1": "value1",
 9            "key2": "value2"
10        }
11    };
12
13    // POSTリクエストを送信する
14    const response = UrlFetchApp.fetch(url, options);
15
16    // レスポンスの内容を取得する
17    const content = response.getContentText();
18
19    Logger.log(`content: ${content}`)
20
21}

指定したURLに対してPOSTリクエストを送信し、レスポンスを取得するサンプルです。 オプションで、ペイロード(=送信するデータ)を設定できます。

ヘッダーしたい

 1function fetchWithHeaders() {
 2    // URLを指定する
 3    const url = "https://httpbin.org/get";
 4
 5    // オプションでヘッダーを設定する
 6    const options = {
 7        "method": "get",
 8        "headers": {
 9            "Authorization": "Bearer ACCESS_TOKEN",
10            "Accept": "application/json"
11        }
12    };
13
14    // リクエストを送信
15    const response = UrlFetchApp.fetch(url, options);
16
17    // レスポンスの内容を取得する
18    const content = response.getContentText();
19    Logger.log(`content: ${content}`)
20
21    const json = JSON.parse(content);
22    Logger.log(`json: ${json}`)
23}

Bearerトークンを使った認証のサンプルです。 その他のオプションは以下のとおりです。

 1const options = {
 2    "method": "get",  // "post", "put", "delete"
 3    "headers": {},
 4    "payload": {},
 5    "muteHttpExceptions": false,
 6    "followRedirects": true,
 7    "timeoutMs": 5000,  // 5 [sec]
 8    "validateHttpsCertificates": true
 9    "contentType": "application/x-www-form-urlencoded",
10    "escaping": true,
11}

Slackに通知したい

 1function sendToSlack() {
 2    // Incoming Webhooksを有効にする
 3    const webhookUrl = "https://hooks.slack.com/services/トークン";
 4
 5    // 通知する内容
 6    const message = {
 7        "channel" : "チャンネル名",
 8        "username": "通知ボットの名前",
 9        "attachments":[{
10            //データ一式
11        }],
12        "icon_emoji": "絵文字コード",
13    };
14
15    // 通知内容をJSON形式に変換
16    const payload = JSON.stringify(message);
17
18    // リクエストのオプション
19    // POST で payloadを追加
20    const options = {
21        "method" : "POST",
22        "contentType": "application/json",
23        "payload": payload,
24        "muteHttpExceptions": true
25    }
26    // データをSlackにPOSTする
27    const response = UrlFetchApp.fetch(url, options);
28
29    // レスポンスの内容で成功/失敗をチェックする
30    const status = response.getResponseCode();
31    Logger.log(`status: ${status}`);    // => 200 / 404
32    const content = response.getContentText();
33    Logger.log(`content: ${content}`);  // => ok  / No service
34}

SlackのIncoming Webhooksアプリを使って、外部サービスからSlackに通知できるようになります。 基本となる手順は以下の通りです。

  1. 通知する内容を作成する

  2. JSON形式に変換する

  3. POSTメソッドでリクエストを送信する

Incoming WebhooksのURLの作り方や、 messageに追加できる値については、 それぞれ適切なドキュメントを参照してください。

Slackのメンバー数を取得したい

  1function getSlackMembers() {
  2    // Slack API Tokenをあらかじめ取得する
  3    // 以下のスコープが必要
  4    // - users:read
  5    // - users.read.email (アドレスを取得する場合)
  6    const token = "SlackのAPIトークン";
  7
  8    // APIのエンドポイント -> JSON形式のデータが返ってくる
  9    const url = "https://slack.com/api/users.list";
 10
 11    // リクエストのオプション
 12    // ヘッダーに認証情報を追加する
 13    const options = {
 14        "method": "get",
 15        "headers": {
 16            "Authorization": "Bearer " + token,
 17        }
 18    };
 19
 20    // リクエスト
 21    const response = UrlFetchApp.fetch(url, options);
 22    const content = response.getContentText();
 23    const data = JSON.parse(content);
 24
 25    if (data.ok) {
 26        const members = data.members.map(function(member) {
 27            const item = {
 28                "id": member.id,
 29                "name": member.name,
 30                "real_name": member.real_name,
 31                "email": member.profile.email || "no_mail",
 32                "is_bot": member.is_bot
 33            };
 34            return item;
 35            }
 36        );
 37        return members;
 38
 39        // 次の forループ に相当
 40        // const members = [];
 41        // for (let i = 0; i < data.members.length; i++) {
 42        //    const member = data.members[i];
 43        //    const item = {
 44        //        "id": member.id,
 45        //        "name": member.name,
 46        //        "real_name": member.real_name,
 47        //        "email": member.profile.email || "no_mail",
 48        //    };
 49        //    members.push(item);
 50        //    };
 51        // return members;
 52    } else {
 53        Logger.log(`Error: ${data.error}`);
 54    };
 55};
 56
 57function writeToSheet() {
 58    // 指定したスプレッドシートを取得
 59    const sheetId = "シートID"
 60    const book = SpreadsheetApp.openById(sheetId);
 61
 62    // メンバー数を記録するシート
 63    let sheet_counter = book.getSheetByName("slackCounter");
 64    if (!sheet_counter){
 65        sheet_counter = book.insertSheet("slackCounter");
 66        sheet_counter.appendRow(["更新日", "メンバー数"])
 67    }
 68
 69    // メンバー情報を記録するシート
 70    let sheet_roster = book.getSheetByName("slackRoster");
 71    if (!sheet_roster) {
 72        sheet_roster = book.insertSheet("slackRoster");
 73    }
 74
 75    // Slackの情報を取得
 76    const members = getSlackMembers();
 77    if (!members || members.length === 0) {
 78        Logger.log("メンバー情報の取得に失敗");
 79        return;
 80    }
 81
 82    // 見出し行を取得
 83    const headers = Object.keys(members[0]);
 84
 85    // メンバー情報を2次元配列に変換
 86    const data = members.map(member => headers.map(header => member[header] || ""));
 87    //
 88    // 次のforループに相当
 89    // const data = [];
 90    // for (let i = 0; i < members.length; i++) {
 91    //     const member = members[i];
 92    //     const row = [];
 93    //     for (let j = 0; j < headers.length; j++) {
 94    //         const header = headers[j]
 95    //         const item = member[header] || ""
 96    //         row.push(item);
 97    //     }
 98    //     data.push(row);
 99    // }
100
101    // データを出力する
102
103    // 1. 既存のシートにメンバー数を追記する
104    // 実行した時刻を最終更新日とする
105    const now = new Date();
106    const lastUpdated = Utilities.formatDate(now, "JST", "yyyy-MM-dd HH:mm:ssZ");
107    sheet_counter.appendRow([lastUpdated, members.length]);
108
109    // 2. 現在のメンバー情報をシートに書き出す
110    // 既存のシートをクリア
111    sheet_roster.clear();
112    sheet_roster.appendRow(headers);
113    const nrows = data.length;
114    const ncols = headers.length;
115    const range = sheet_roster.getRange(2, 1, nrows, ncols);
116    range.setValues(data);
117}

Slack APIトークンのスコープは以下を設定します。

  • users:read

  • users:read.email(メールアドレスを取得する場合

取得できるユーザー情報のサンプル

  • id

  • name

  • real_name

  • is_admin

  • is_owner

  • is_primary_owner

  • is_bot

  • updated

  • profile.email

  • profile.real_name (= real_name)

  • profile.display_name

dataの構造

{
    "ok": true,
    "members": [
        {
            "id": "ユーザーID",
            "team_id": "ワークスペースID",
            "name": "ユーザー名",
            ...
            "profile": {
                "email": "メールアドレス",
                ...
            },
            "is_bot": false,
            ...
        },
        {
            "id": "次のユーザーID",
            ...
        }
        // 他のメンバーの情報
    ]
}

GitLabにコミットしたい

 1function commitToGitLab(data) {
 2    // data: コミットしたい内容
 3
 4    // GitLabのAPIエンドポイント
 5    const projectId = "プロジェクトID"
 6    const filePath = "ファイルパス"
 7    const url = `https://gitlab.com/api/v4/${projectId}/repository/files/${filePath}`;
 8
 9    // GitLabのPersonal API Token (PAT)
10    const token = "GitLabのPAT"
11
12    const content = {
13        branch: "main",
14        commit_message: "Update from Google Sheets",
15        content: data,
16        encoding: "base64",
17    };
18    const payload = JSON.stringify(content);
19
20    const options = {
21        method: "put,
22        headers: {
23            "PRIVATETOKEN": token,
24            "Content-Type": "application/json"
25        },
26        payload: payload,
27    };
28
29    const response = UrlFetchApp.fetch(url, options);
30    const status = response.getResponseCode();
31    Logger.log(`status: ${status}`);
32}

GitLabにマージリクエストしたい

  1function pushDataToGitLabWithMR() {
  2
  3    const projectId = "GitLabのプロジェクトID";
  4    const token = "GitLabのPAT";
  5
  6    // 実行時のタイムスタンプを使ってユニークなブランチ名を作成
  7    // シートの入力されたタイムスタンプでもいいかも
  8    const branchName = "update-from-google-sheet-" + new Date().getTime();
  9
 10    const check = checkBranchExists(projectId, branchName);
 11    if ( !check ) {
 12        createNewBranch(projectId, branchName, "main", token);
 13    };
 14    commitToBranch(projectId, branchName, "data.csv", content, token);
 15    createMergeRequest(projectId, branchName, "main", title, description, token);
 16}
 17
 18function createNewBranch(
 19    projectId,
 20    newBranchName,
 21    baseBranchName,
 22    token
 23    ) {
 24        const url = `https://gitlab.com/api/v4/projects/${projectId}/repository/branches`;
 25
 26        const payload = {
 27            branch: newBranchName,
 28            ref: baseBranchName
 29        };
 30
 31        const options = {
 32            method: "post",
 33            headers: {
 34                "PRIVATE-TOKEN": token,
 35                "Content-Type": "application/json"
 36            },
 37            payload: JSON.stringify(payload)
 38        };
 39
 40        const response = UrlFetchApp.fetch(url, options);
 41        const status = response.getResponseCode();
 42        const body = response.getContentText();
 43        Logger.log(`createNewBranch: ${status}: ${body}`);
 44    };
 45
 46function commitToBranch(
 47    projectId,
 48    branchName,
 49    filePath,
 50    fileContent,
 51    token
 52    ) {
 53        const url = `https://gitlab.com/api/v4/projects/${projectId}/repository/files/${encodeURIComponent(filePath)}`;
 54
 55        const payload = {
 56            branch: branchName,
 57            commit_message: "Googleシートのデータを追加",
 58            content: Utilities.base64Encode(fileContent),
 59            encoding: "base64"
 60        };
 61
 62        const options = {
 63            method: "put",
 64            headers: {
 65                "PRIVATE-TOKEN": token,
 66                "Content-Type": "application/json"
 67            },
 68            payload: JSON.stringify(payload)
 69        };
 70
 71        const response = UrlFetch(url, options);
 72        const status = response.getResponseCode();
 73        const body = response.getContentText();
 74        Logger.log(`commitToBranch: ${status}: ${body}`)
 75
 76    };
 77
 78function createMergeRequest(
 79    projectId,
 80    sourceBranchName,
 81    targetBranchName,
 82    title,
 83    description,
 84    token
 85    ) {
 86        const url = `https://gitlab.com/api/v4/projects/${projectId}/merge_requests`;
 87        const payload = {
 88            source_branch: sourceBranchName,
 89            target_branch: targetBranchName,
 90            title: title,
 91            description: description,
 92            remove_source_branch: true
 93        };
 94
 95        const options = {
 96            method: "post",
 97            headers: {
 98                "PRIVATE-TOKEN": token,
 99                "Content-Type": "application/json"
100            },
101            payload: JSON.stringify(payload)
102        };
103
104        const response = UrlFetchApp.fetch(url, options);
105        const status = response.getResponseCode();
106        const body = response.getContentText();
107        Logger.Log(`createMergeRequest: ${status}: ${body}`);
108    }
109
110function checkBranchExists(
111    projectId,
112    branchName,
113    token
114    ) {
115        const url = `https://gitlab.com/api/v4/projects/${projectId}/repository/branches/${encodeURIComponent(branchName)}`;
116        const options = {
117            method: "get",
118            headers: {
119                "PRIVATE-TOKEN": token
120            }
121        };
122
123        const response = UrlFetchApp.fetch(url, options);
124        const status = response.getResponseCode();
125        const body = response.getContentText();
126        Logger.log(`checkBranchExists: ${status}: ${body}`);
127
128        if (status === 200) {
129            // ブランチが存在する場合
130            return true;
131        } else {
132            // ブランチが存在しない場合
133            return false;
134        };
135    };

GoogleシートのデータをGitLabに追加することを想定したサンプルです。 mainブランチに直接コミットするのではなく、マージリクエストを作成しています。

  1. mainブランチから新規ブランチを作成する

  2. 作成したブランチにコミットする

  3. マージリクエストを作成する