Google Apps Script(GAS)からBox APIを叩くためのすべて
四苦八苦してしまって本当に辛かったので、他の人が同じような苦労をしないように・・・
個人アカウントのOAuth認証で良い場合はこのサイトの手順が参考になります。
How to Use the Box API with Google Apps Script - Digital Inspiration
ただ今回は、AppSheetからの呼び出しで使いたかったので、これだと用途に合わないんですよね。
必要なこと
ざっくりですが、以下の作業が必要です。
- Boxの開発アプリをCustom AppのServer Authenticationで作成
- Box Adminでアプリを承認
- BoxアプリのService Account IDを操作したいBoxフォルダの共有に追加
- GASの実行権限設定
- Box APIからアクセストークンの取得
Box側
1. 開発アプリの作成
Boxの開発アプリをCustom AppのServer Authenticationで作成します。
※途中で設定を日本語にしたので、図ではサーバー認証(クライアント資格情報許可)
です
構成での作業
2. アプリのEnterprise承認をする
アプリの設定が終わったら承認リクエストを飛ばします。
そうするとBox Adminの権限があるメンバーにアプリ承認のリクエストが飛ぶので、承認してください。
GAS側
GASのコードはclaspを使って作成しています。
ここは特に真似る必要はありませんが、TypeScriptでのdoPost関数の実装例として見て貰えればと。
結局nodeライブラリは使わなかったのですが、claspの使い方はこのサイトを参考にさせて貰いました。
appsscript.jsonの中身
{ "timeZone": "Asia/Tokyo", "dependencies": {}, "exceptionLogging": "STACKDRIVER", "oauthScopes": [ "https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/script.external_request" ], "runtimeVersion": "V8" }
main.tsの全量
重要なのはアクセストークンを取得しているgetAccessTokenで、他は各自の処理に合わせて貰えればOKです。
const BOX_CLIENT_ID = 'クライアントID'; const BOX_CLIENT_SECRET = 'クライアントシークレット'; const BOX_ENTERPRISE_ID = '組織ID'; const BOX_TEMPLATE_FOLDER_ID = 'コピー元フォルダのID'; const BOX_PARENT_FOLDER_ID = 'コピー先(親)フォルダのID'; // https://developers.google.com/apps-script/guides/web#request_parameters export function doPost(e: GoogleAppsScript.Events.DoPost): GoogleAppsScript.Content.TextOutput { const contents = JSON.parse(e.postData.contents); const orderDate = contents["orderDate"]; const customerName = contents["customerName"]; const createFolderId = copyFolder(orderDate, customerName); const resultParams = {folderId: createFolderId}; const result = JSON.stringify(resultParams); return ContentService.createTextOutput(result); } const getAccessToken = (): string => { const endpoint = 'https://api.box.com/oauth2/token'; const payload = { client_id: BOX_CLIENT_ID, client_secret: BOX_CLIENT_SECRET, grant_type: 'client_credentials', box_subject_type: 'enterprise', box_subject_id: BOX_ENTERPRISE_ID }; const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; const response = UrlFetchApp.fetch(endpoint, { headers: headers, method: 'post', payload: payload }); const json = JSON.parse(response.getContentText()); return json.access_token; }; const copyFolder = (orderDate: string, customerName: string): string => { const endpoint = `https://api.box.com/2.0/folders/${BOX_TEMPLATE_FOLDER_ID}/copy`; const access_token = getAccessToken(); const headers = { 'Authorization': 'Bearer ' + access_token, "Content-type": "application/json", }; const payload = { name: `${orderDate}_${customerName}`, parent: { id: BOX_PARENT_FOLDER_ID } }; const response = UrlFetchApp.fetch(endpoint, { headers: headers, method: 'post', payload: JSON.stringify(payload) }); const json = JSON.parse(response.getContentText()); Logger.log(json.id); return json.id; };
以上です。
落ち穂拾い
Client Credentials Grantの日本語ページがない
今回のやり方のベースになっている、以下のページに該当する日本語のページがありません。
Boxの開発ドキュメントは日本語のものが用意されており、 そちらが最初に表示されたので、別段気にしていなかったのですが、 クライアントクレデンシャルでのアクセストークン取得方法のページはなぜかガッツリ抜け落ちていました。
英語
日本語
Boxで最初に企業ドメインアカウントで開発者登録をすると、その人が管理者になる
ADMINは、他のアカウントへのスイッチもできるので、適当なタイミングで適切な人に権限を渡しましょう。
https://support.box.com/hc/ja/articles/360044194953/
AppSheetはPOSTのレスポンスを使えない
本記事の例ではdoPostでレスポンスを返していますが、これを呼び出すAppSheetは現状レスポンスの中身を利用できないので、 あの部分はなくても問題ありません。
GASでデプロイ後はGCP連携していないとログが表示されない
GASをデプロイし、外部からGASのスクリプトをcurlなどで叩いた場合、GCP連携していないとコード中に組み込んだログは表示されません。