複数のAPIを呼ぶとき、1つが429、もう1つが200だった結果を、まとめて「失敗」とすると原因を追えません。GASのfetchAllで受け取った応答は、要求ごとの名前とHTTPコードを組にして整理します。
一度に渡す件数を増やせば問題が解決するわけではありません。利用先の制限とGASの割当があり、要求全体が例外で終わる場合もあります。最初は少数の読み取り要求に絞り、応答を受け取れた場合の失敗と、通信自体の失敗を分けます。
要求の名前とURLを先にそろえる
公式のUrlFetchAppでは、fetchAllへURLや要求オブジェクトの配列を渡し、各入力要求に対するHTTPResponseの配列を受け取ります。結果を独自に完了順へ並べ替えず、要求の配列の位置と対応させます。
以下はJSONを返す読み取り用エンドポイントを想定し、例独自の上限を5件にしています。URLやキーがログへ広がらないよう、結果に出す識別名はcatalog・stockのような短い名前へ分けます。
例のURLは説明用です。実際に試すときは、自分が利用を認められた読み取り用URLへ置き換え、認証や取得頻度の条件を確認してください。投稿や送信を伴う要求は入れません。
HTTP失敗とJSON解析失敗を分けるコード
muteHttpExceptions:trueにより、HTTPの失敗コードも応答として整理する指定を入れます。通信の例外は外側へ返し、全部成功したような空配列へ置き換えません。
function inspectFetchAll(targets, fetchAll) {
if (!Array.isArray(targets) || targets.length < 1 || targets.length > 5) {
throw new Error('要求は1〜5件で指定してください');
}
const requests = targets.map(function (target) {
if (!target.key || !/^https:\/\//.test(target.url)) throw new Error('要求名とHTTPS URLを確認');
return {url: target.url, method: 'get', muteHttpExceptions: true};
});
const responses = fetchAll(requests);
if (responses.length !== targets.length) throw new Error('応答件数を確認してください');
return responses.map(function (response, index) {
const code = response.getResponseCode();
let validJson = false;
try { JSON.parse(response.getContentText()); validJson = true; }
catch (error) { /* 本文全体はログへ出しません。 */ }
return {key: targets[index].key, httpStatus: code,
okHttp: code >= 200 && code < 300, validJson: validJson};
});
}
function previewFetchAllStatus() {
const targets = [
{key: 'catalog', url: 'https://example.com/catalog'},
{key: 'stock', url: 'https://example.com/stock'}
];
console.log(JSON.stringify(inspectFetchAll(targets,
requests => UrlFetchApp.fetchAll(requests))));
}
架空のcatalog応答が200でJSON、stock応答が429でJSONなら、前者はokHttp:true、後者はfalseで、validJsonは両方trueです。200でもHTMLが返ればvalidJson:falseになります。HTTP成功と、必要な形式のデータが返ったことは別の判定です。
まとめて例外になった場合
通信そのものが例外になれば、上の関数は結果一覧を返さず止まります。どの要求まで相手へ到達したかを、空の一覧から推測しないようにします。特に更新を伴う要求を後から追加すると、全件再送で重複する可能性があります。
読み取り要求でも、再試行の回数と待機条件は決めておきます。429が1件だけなら、その要求の制限や応答ヘッダーを確認し、正常な要求まで無条件に取り直さないようにします。HTTPResponseの項目は公式資料で確認できます。
件数を増やす前に見ること
JSONとして解析できても、業務で必要な項目や件数がそろうことまでは分かりません。APIごとのデータ形式を検査する段階を、この結果の確認後に置きます。今回の関数は応答状況を見分けるところまでです。
ローカルでは代用fetchAllで、200と429の混在、不正JSON、応答数の違い、通信例外、上限超過を確認しました。実APIへの通信や同時実行速度は計測していません。設定値はPropertiesService、失敗した実行はGASのエラーログで確認する構成にできます。
