HTTPリクエストを送信したい(UrlFetchApp

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

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

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}

指定した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.stringify(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(webhookUrl, 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        Logger.log(`Error: ${data.error}`);
27        return [];
28    }
29
30    return data.members.map(member => ({
31        "id": member.id,
32        "name": member.name,
33        "real_name": member.real_name,
34        "email": member.profile.email || "no_mail",
35        "is_bot": member.is_bot
36    }));
37}
38
39function writeToSheet() {
40    // 指定したスプレッドシートを取得
41    const sheetId = "シートID";
42    const book = SpreadsheetApp.openById(sheetId);
43
44    // メンバー数を記録するシート
45    let sheetCounter = book.getSheetByName("slackCounter");
46    if (!sheetCounter) {
47        sheetCounter = book.insertSheet("slackCounter");
48        sheetCounter.appendRow(["更新日", "メンバー数"]);
49    }
50
51    // メンバー情報を記録するシート
52    let sheetRoster = book.getSheetByName("slackRoster");
53    if (!sheetRoster) {
54        sheetRoster = book.insertSheet("slackRoster");
55    }
56
57    // Slackの情報を取得
58    const members = getSlackMembers();
59    if (!members || members.length === 0) {
60        Logger.log("メンバー情報の取得に失敗");
61        return;
62    }
63
64    // 見出し行を取得
65    const headers = Object.keys(members[0]);
66
67    // メンバー情報を2次元配列に変換
68    const data = members.map(member => headers.map(header => member[header] || ""));
69
70    // 1. 既存のシートにメンバー数を追記する
71    // 実行した時刻を最終更新日とする
72    const now = new Date();
73    const lastUpdated = Utilities.formatDate(now, "JST", "yyyy-MM-dd HH:mm:ssZ");
74    sheetCounter.appendRow([lastUpdated, members.length]);
75
76    // 2. 現在のメンバー情報をシートに書き出す
77    // 既存のシートをクリア
78    sheetRoster.clear();
79    sheetRoster.appendRow(headers);
80    const nrows = data.length;
81    const ncols = headers.length;
82    const range = sheetRoster.getRange(2, 1, nrows, ncols);
83    range.setValues(data);
84}

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

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

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

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

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