Google Apps Scriptで外部APIを呼び出す基本:UrlFetchAppでGET・POST・認証つきリクエストを書く
Google Apps Script(GAS)で外部APIを呼び出すなら、中心になるのは UrlFetchApp です。スプレッドシートのデータを外部サービスへ送る、Web APIからJSONを取得して表に反映する、WordPressや社内ツールと連携するといった処理を、GASだけで組み立てられます。
この記事では、UrlFetchApp.fetch() の基本形から、GET、POST、JSON、APIキー、エラー処理、よくある失敗までを実務寄りに整理します。対象は、Apps Scriptで初めて外部API連携を書く人、または「サンプルは動いたが、認証やエラー処理でつまずく」人です。
UrlFetchApp.fetch(url)で外部URLへHTTP/HTTPSリクエストを送れる- JSON APIを扱うときは
JSON.parse()とJSON.stringify()をセットで使う - APIキーはコードに直書きせず、
PropertiesServiceなどに分けて置く - 実務では
muteHttpExceptions: trueでレスポンス内容を確認しながら原因を切り分ける - GASには実行時間、URL Fetch回数、レスポンスサイズなどの制限がある
確認時点は 2026年7月8日 です。Google Apps Scriptの公式リファレンスでは、UrlFetchApp は外部ホストやWeb上のリソースへHTTP/HTTPSリクエストを送るサービスとして説明されています。
前提環境:GASから外部APIを呼ぶと何が起きるか
UrlFetchApp は、GASから外部のWebサーバーへリクエストを送り、返ってきたレスポンスを受け取るための標準サービスです。
たとえば、次のような場面で使います。
- スプレッドシートの商品コードを外部APIへ送り、価格や在庫を取得する
- 問い合わせフォームの内容をチャットツールやCRMへ送る
- WordPress REST APIへ下書き記事やメタ情報を送信する
- サーバー監視APIからステータスを取得して、異常時だけメール通知する
GAS側から見ると、外部API連携は大きく3つに分かれます。
- URLへアクセスする
- 必要ならヘッダーや本文を付ける
- 返ってきた本文やステータスコードを読む
UrlFetchApp の主なメソッドは次の通りです。
| メソッド | 主な用途 |
|---|---|
fetch(url) |
1つのURLへ単純なリクエストを送る |
fetch(url, params) |
メソッド、ヘッダー、本文などを指定して送る |
fetchAll(requests) |
複数のURLへまとめてリクエストを送る |
getRequest(url, params) |
実際に送る前にリクエスト内容を確認する |
ここがポイント: GASでAPI連携を書くときは、まず「URL」「HTTPメソッド」「ヘッダー」「本文」「レスポンスコード」の5点を分けて見ると、エラー原因を追いやすくなります。
まずはGETでJSONを取得する
外部APIの読み取りだけなら、最初はGETリクエストから始めるのが分かりやすいです。
ここでは、公開テスト用APIの https://jsonplaceholder.typicode.com/posts/1 からJSONを取得する例で説明します。実務では、天気API、在庫API、CMS APIなどに置き換えて考えられます。
function fetchPost() {
const url = 'https://jsonplaceholder.typicode.com/posts/1';
const response = UrlFetchApp.fetch(url);
const statusCode = response.getResponseCode();
const text = response.getContentText();
const data = JSON.parse(text);
Logger.log(statusCode);
Logger.log(data.title);
}
入力例
このコードでは、次のURLへアクセスします。
https://jsonplaceholder.typicode.com/posts/1
出力例
ログには、HTTPステータスコードとJSON内の title が表示されます。
200
sunt aut facere repellat provident occaecati excepturi optio reprehenderit
getContentText() はレスポンス本文を文字列として取り出します。JSON APIの返り値は文字列のままでは扱いにくいため、JSON.parse() でJavaScriptオブジェクトに変換します。
ここで大事なのは、APIの戻り値をいきなり使わず、ステータスコードと本文を分けて確認することです。成功時は 200、作成成功なら 201、認証エラーなら 401、権限不足なら 403、存在しないURLなら 404 など、数字を見るだけで切り分けが早くなります。
POSTでJSONを送信する書き方
外部サービスへデータを送る場合は、method: 'post'、contentType: 'application/json'、payload: JSON.stringify(...) を組み合わせます。
function createPost() {
const url = 'https://jsonplaceholder.typicode.com/posts';
const body = {
title: 'GASから送信したテスト投稿',
body: 'UrlFetchAppでJSONをPOSTする例です。',
userId: 1
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(body),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
const statusCode = response.getResponseCode();
const responseBody = response.getContentText();
Logger.log(statusCode);
Logger.log(responseBody);
}
入力データ
GAS内では、まず通常のオブジェクトとしてデータを作ります。
const body = {
title: 'GASから送信したテスト投稿',
body: 'UrlFetchAppでJSONをPOSTする例です。',
userId: 1
};
APIへ送る直前に、JSON.stringify(body) でJSON文字列に変換します。
出力例
テストAPIでは、作成されたように見えるJSONが返ります。
{
"title": "GASから送信したテスト投稿",
"body": "UrlFetchAppでJSONをPOSTする例です。",
"userId": 1,
"id": 101
}
実務では、ここで返ってきた id や status をスプレッドシートへ書き戻すことが多いです。たとえば「送信済み」「APIの受付番号」「エラー理由」を行ごとに残しておくと、後から再送や確認がしやすくなります。
APIキーやBearerトークンを付ける
認証が必要なAPIでは、ヘッダーにAPIキーやBearerトークンを付けます。形式はAPIによって違いますが、よく使うのは Authorization ヘッダーです。
function fetchWithBearerToken() {
const url = 'https://api.example.com/v1/items';
const token = PropertiesService
.getScriptProperties()
.getProperty('API_TOKEN');
const options = {
method: 'get',
headers: {
Authorization: `Bearer ${token}`
},
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
Logger.log(response.getResponseCode());
Logger.log(response.getContentText());
}
PropertiesService.getScriptProperties() は、スクリプト単位で参照できるキー・バリュー形式の保存先です。APIキーやトークンをコードに直接書くより、値を差し替えやすく、ソース共有時の漏えいも減らせます。
ただし、スクリプトの編集権限を持つ人には参照され得ます。社外秘の認証情報を扱う場合は、次の点を確認してください。
- GitHubや共有ドライブにAPIキーを書いたコードを置かない
- ログにトークン全文を出さない
- 退職者や外部委託者の編集権限を残さない
- 可能ならAPI側でキーの権限、IP制限、有効期限を絞る
- 漏えいした可能性があれば、API側でキーを再発行する
GASは手軽ですが、認証情報を扱う時点で運用の責任も発生します。試作コードのまま本番のAPIキーを入れないことが、最初の防御になります。
よく使うオプションを押さえる
fetch(url, params) の params には、HTTPメソッドやヘッダー以外にも実務でよく使う指定があります。
| オプション | 使う場面 |
|---|---|
method |
get、post、put、patch、delete を指定する |
headers |
APIキー、Bearerトークン、独自ヘッダーを付ける |
contentType |
JSON送信時に application/json を指定する |
payload |
POSTやPUTで送る本文を指定する |
muteHttpExceptions |
4xx/5xxでも例外で止めず、レスポンス本文を確認する |
followRedirects |
リダイレクトを自動追跡するか指定する |
timeoutSeconds |
リクエスト完了まで待つ秒数を指定する |
特に初心者がつまずきやすいのは muteHttpExceptions です。初期状態では、失敗ステータスのときに例外で止まり、APIが返したエラーメッセージを見落とすことがあります。
原因調査中は、次のようにレスポンスをログに出すと状況をつかみやすくなります。
function debugRequest() {
const url = 'https://api.example.com/v1/items';
const options = {
method: 'get',
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
Logger.log(`status: ${response.getResponseCode()}`);
Logger.log(response.getContentText());
}
本番運用では、全文ログを出し続けると個人情報や認証情報が残る可能性があります。調査が終わったら、必要な項目だけ記録する形に変えてください。
NG例と改善例:JSON送信で失敗しやすい書き方
JSON APIでよくある失敗は、JavaScriptオブジェクトをそのまま payload に入れてしまうことです。
NG例
function badPost() {
const url = 'https://api.example.com/v1/items';
const body = {
name: 'sample',
count: 3
};
const options = {
method: 'post',
contentType: 'application/json',
payload: body
};
UrlFetchApp.fetch(url, options);
}
この書き方では、APIが期待するJSON文字列として送られない可能性があります。公式リファレンスでも、JSON payloadを送る例ではJavaScriptオブジェクトを JSON.stringify() で文字列に変換しています。
改善例
function goodPost() {
const url = 'https://api.example.com/v1/items';
const body = {
name: 'sample',
count: 3
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(body),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
Logger.log(response.getResponseCode());
Logger.log(response.getContentText());
}
JSON APIへ送る本文は、最後に文字列へ変換する。このルールを覚えておくと、GASから多くのREST APIを扱いやすくなります。
実務での使いどころ:スプレッドシートとAPIをつなぐ
GASの強みは、スプレッドシートやGoogleフォームのデータをそのままAPI連携に使えることです。
たとえば、シートに次のようなデータがあるとします。
| A列 | B列 | C列 |
|---|---|---|
| item_id | name | status |
| 1001 | サンプルA | 未送信 |
| 1002 | サンプルB | 未送信 |
未送信の行だけ外部APIへ送るなら、次のような流れになります。
function sendRowsToApi() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('items');
const values = sheet.getDataRange().getValues();
const url = 'https://api.example.com/v1/items';
for (let i = 1; i < values.length; i++) {
const [itemId, name, status] = values[i];
if (status !== '未送信') {
continue;
}
const body = {
itemId: itemId,
name: name
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(body),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
const statusCode = response.getResponseCode();
if (statusCode >= 200 && statusCode < 300) {
sheet.getRange(i + 1, 3).setValue('送信済み');
} else {
sheet.getRange(i + 1, 3).setValue(`エラー:${statusCode}`);
}
}
}
この例では、成功した行だけ 送信済み に変えています。途中でエラーが出ても、どの行まで処理できたかがシート上に残ります。
実務ではさらに、次の列を追加すると運用しやすくなります。
last_sent_at: 最後に送信した日時response_code: APIのステータスコードerror_message: APIが返したエラー理由retry_count: 再送回数
ここまで入れておくと、「同じ行を何度も送ってしまう」「エラー理由が分からず再実行できない」といった事故を減らせます。
制限とエラー対処:GASだけで抱え込みすぎない
UrlFetchApp は便利ですが、無制限にAPIを呼べるわけではありません。
Googleのクォータ資料では、URL Fetch callsはコンシューマーアカウントで1日20,000回、Google Workspaceアカウントで1日100,000回とされています。また、URL FetchのレスポンスサイズやPOSTサイズにも制限があります。クォータは変更される可能性があるため、本番運用前に公式情報を確認してください。
よくあるエラーと見るべき点は次の通りです。
| 状況 | 主な原因 | 確認すること |
|---|---|---|
401 Unauthorized |
認証情報がない、期限切れ | APIキー、Bearerトークン、OAuth設定 |
403 Forbidden |
権限不足、IP制限 | API側の権限、GASからのアクセス許可 |
404 Not Found |
URLやエンドポイント間違い | APIドキュメントのパス、バージョン |
429 Too Many Requests |
API側のレート制限 | 呼び出し回数、待機時間、再試行ルール |
500 系 |
API側の一時障害 | レスポンス本文、時間を置いた再試行 |
| GASのクォータ例外 | GAS側の利用上限 | 実行回数、トリガー頻度、まとめ処理 |
連続実行では待機や分割を入れる
大量の行を1件ずつAPIへ送る処理では、相手側APIのレート制限に引っかかることがあります。APIドキュメントに「1分あたり何回まで」といった制限がある場合は、それに合わせて処理を分けます。
簡単な待機なら Utilities.sleep() を使えます。
Utilities.sleep(1000); // 1秒待つ
ただし、待機を増やしすぎるとGASの実行時間制限に近づきます。大量データを扱うなら、トリガーで分割実行する、送信済みステータスを残して続きから処理する、サーバー側のバッチ処理へ移す、といった設計が必要です。
fetchAll() は速くなるが、相手APIへの負荷も増える
複数URLをまとめて呼ぶなら UrlFetchApp.fetchAll() も使えます。
function fetchMultipleUrls() {
const requests = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3'
];
const responses = UrlFetchApp.fetchAll(requests);
responses.forEach((response) => {
Logger.log(response.getResponseCode());
Logger.log(JSON.parse(response.getContentText()).title);
});
}
一覧取得や複数ページの取得には便利です。一方で、短時間に複数のリクエストを投げるため、相手側APIの制限には注意してください。速さだけで選ばず、APIの利用規約とエラー時の再試行方法を先に確認するのが実務では安全です。
代替手段との使い分け
GASの UrlFetchApp は、Google Workspace周辺の小さな自動化に向いています。ただし、すべてのAPI連携をGASで作る必要はありません。
| 方法 | 向いている場面 | 注意点 |
|---|---|---|
| GAS + UrlFetchApp | スプレッドシート、フォーム、GmailとAPIをつなぐ小規模処理 | 実行時間、クォータ、認証情報管理に注意 |
| Power Automate / Make / Zapier | ノーコードでSaaS同士をつなぐ | 細かい例外処理や料金体系を確認する |
| Node.js / Python | 大量データ、複雑な認証、継続的なバッチ処理 | 実行環境とデプロイ運用が必要 |
| WordPressプラグインやサーバー側PHP | WordPress内の処理として完結させたい場合 | テーマやプラグイン更新、セキュリティ対策が必要 |
判断の目安はシンプルです。スプレッドシートを起点に、数百件程度のデータを定期的に送るならGASは有力です。数万件の処理、厳密な再試行、長時間実行、複数サービスの認証をまとめて扱うなら、サーバー側のスクリプトや専用ワークフローも検討してください。
実装前のチェックリスト
API連携は、コードを書き始める前の確認で失敗をかなり減らせます。
- APIドキュメントでエンドポイントURLとHTTPメソッドを確認したか
- GETなのかPOSTなのか、本文が必要なのかを確認したか
Content-Typeはapplication/jsonでよいか- APIキー、Bearerトークン、OAuthなど認証方式を確認したか
- エラー時のレスポンス本文を確認できるようにしたか
- GAS側とAPI側の回数制限を確認したか
- ログに個人情報や認証情報を出していないか
- 再実行しても同じデータを二重送信しない設計になっているか
UrlFetchApp の基本は難しくありません。難しくなるのは、認証、エラー、再実行、回数制限が絡んだときです。
最初の一歩は、GETでステータスコードと本文を見ること。次にPOSTでJSONを送ること。その後で、認証情報の保管、エラー時の記録、再送できるシート設計へ進むと、実務で壊れにくいAPI連携になります。
次に見るべきポイントは、使いたいAPIの認証方式です。APIキーだけで済むのか、OAuthが必要なのかで、GAS側の設計は大きく変わります。
