はじめに
最近、社内業務の効率化のために、Google Apps Script (GAS) を使って freee と連携する社内ツールを作成することになりました。
その際、エンドポイントごとにリクエスト処理を書くのは非効率だったため、GET と POST の両方に対応し、エラーハンドリングやトークン処理を共通化した汎用関数を作成しました。 今回はその実装コードを共有します。
まとめ
本記事で紹介するコードのポイントは以下の通りです。
- GET / POST の共通化: メソッド指定とペイロード有無で挙動を切り替え
- エラーハンドリング: muteHttpExceptions: true を設定し、APIエラー時もスクリプトを停止させずにレスポンスを確認可能にする
- JSONパースの自動化: 成功時は自動でパースしたオブジェクトを返す
- レートリミットへの配慮: ヘッダー情報を確認するフックを用意(拡張用)
コード
以下が作成した汎用関数と、それを呼び出すラッパー関数です。
※ getService() は「GASのOAuth2ライブラリ」等を使用した認証サービス取得関数を実装します。
/**
* freee APIへのリクエストを共通処理する関数
* @param {string} method - 'get' or 'post'
* @param {string} requestUrl - API URL
* @param {Object} [payload] - POST時のデータ (省略可)
* @returns {Object} - パース済みのJSONデータ、またはエラー時はnull/エラーオブジェクト
*/
function callFreeeApi(method, requestUrl, payload) {
var freeeApp = getService(); // OAuth2サービスを取得
// 1. アクセストークンの確認
if (!freeeApp.hasAccess()) {
console.error('アクセストークンがありません。認証してください。');
return null; // または例外をスロー
}
const accessToken = freeeApp.getAccessToken();
const headers = { "Authorization" : "Bearer " + accessToken };
// 2. オプション設定
const options = {
'method' : method,
'headers': headers,
'muteHttpExceptions': true // エラー時も例外を投げず、レスポンスを受け取る
};
if (method === 'post' && payload) {
options.contentType = 'application/json';
options.payload = JSON.stringify(payload);
}
try {
// 3. フェッチ実行
var response = UrlFetchApp.fetch(requestUrl, options);
var responseCode = response.getResponseCode();
var responseHeader = response.getAllHeaders();
var responseContent = response.getContentText();
// 4. レートリミット情報の確認 (エラー時でもヘッダーを確認するためここで呼ぶ)
if (typeof getRateLimitInfo === 'function') {
getRateLimitInfo(responseHeader); // 別途実装
}
// 5. ステータスコードによる分岐
if (responseCode >= 200 && responseCode < 300) {
// 成功時:JSONパースして返す
console.log(`Success (${responseCode}): ${requestUrl}`);
return JSON.parse(responseContent);
} else {
// APIエラー時 (40x, 50xなど)
console.error(`Error (${responseCode}): ${requestUrl}`);
console.error(`Response: ${responseContent}`);
// 呼び出し元にエラー内容を含んだオブジェクトを返却
return {
error: true,
code: responseCode,
message: responseContent
};
}
} catch (e) {
// ネットワークエラーやJSONパースエラーなどの予期せぬ例外
console.error('Exception occurred: ' + e.toString());
return { error: true, message: e.toString() };
}
}
// 6. ラッパー関数
function callGetApi(requestUrl) {
return callFreeeApi('get', requestUrl);
}
function callPostApi(requestUrl, body) {
return callFreeeApi('post', requestUrl, body);
}
コードの説明
主な処理の流れは以下の通りです。
- アクセストークンの確認
-
getService()でOAuth2サービスを取得し、トークンがあるかチェックします。AuthorizationヘッダーにBearerトークンをセットします。
-
- オプション設定
-
muteHttpExceptions: trueの設定UrlFetchApp.fetchのオプションでここをtrueにすることで、API側から 400 や 500 番台のエラーが返ってきても、GAS側で即座に例外落ちせず、エラーレスポンスの中身(エラーメッセージ等)をハンドリングできるようにしています。
-
- xxx
- POST時のペイロード処理 メソッドが
postでpayloadがある場合のみ、contentTypeをapplication/jsonに設定し、データをJSON文字列化してセットします。
- POST時のペイロード処理 メソッドが
- レートリミットの確認
- レートリミットの確認 freee APIにはレートリミット(利用制限)があります。
リミット情報はレスポンスヘッダーに含まれるため、成功・失敗に関わらずresponseHeaderを取得し、別途用意した関数getRateLimitInfoに渡してチェックできるようにしています。
- レートリミットの確認 freee APIにはレートリミット(利用制限)があります。
- ステータスコードによる分岐
- ステータスコードによる分岐
- 200番台 (成功): レスポンスボディを
JSON.parseして返却します。 - エラーハンドリング
それ以外 (エラー): コンソールにエラー内容を出力し、呼び出し元でハンドリングしやすいよう、エラーステータスを含んだオブジェクトを返します。
- 200番台 (成功): レスポンスボディを
- ステータスコードによる分岐
- ラッパー関数
- ラッパー関数
callGetApiとcallPostApiを用意することで、実際の業務ロジックを書く際に、引数をシンプルに保てるようにしています。
- ラッパー関数
おわりに
この汎用関数を用意したことで、個別のAPIを呼ぶ際は「URL」と「パラメータ」を渡すことだけに集中できるようになりました。
freee API連携ツールを作成する際の参考になれば幸いです。
最後に、GMOコネクトではサービス開発支援や技術支援をはじめ、幅広い支援を行っておりますので、何かありましたらお気軽にお問合せください。