freeeに関係ない話題ですが、Google Apps Script(以下GAS)でできる効率化の例として番外編としてfreee API以外のGASでの活用に関しても記事にしています。
今回は、「ある1日にどんな作業にどれだけ時間を使ったのか記録するタイムトラッカーアプリであるClockifyのタイムエントリ(時間記録)をGoogleカレンダーにコピーしてライフログにする」に挑戦したいと思います。
前回の記事では認証方法を確認して、サンプルリクエストを送信し無事レスポンスが返ってくることを確認しました。
今回はTime entry(時間記録)の取得に最低限必要なWorkspaceとUserのIDを取得したいと思います。
あらためてUser情報からIDを取得する
サンプルコードが偶然ログインユーザ情報を確認するスクリプトだったので、それを生かしてUser IDは確認できます。
念の為、あらためてClockify API の公式ドキュメントからUserのエンドポイントを確認します。
これを共通エンドポイントと組み合わせて
https://api.clockify.me/api/v1/user
がUser情報を取得するためのエンドポイントになります。
このエンドポイントにログインユーザーの情報をリクエストして成功した時のレスポンスのサンプルが公式ドキュメントに記載されています。
レスポンスはJSON文字列なのでJSONオブジェクトに変換し、第1階層のidプロパティにUser IDが格納されているがわかります。
ということで、User IDをログ出力するスクリプトはこちら。
function logUserId() {
const apiKey = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_API_KEY'); // API Keyはプロパティストアに格納
const url = 'https://api.clockify.me/api/v1/user'; // Userのエンドポイント
/* Class UrlFetchApp のリファレンスからfetch(url, params)メソッドを確認しパラメーターの書き方を読み替える */
const params = {
contentType: 'application/json',
headers: { 'X-Api-Key': apiKey },
muteHttpExceptions: true // レスポンスが失敗した場合でもエラーを出さずにHTTPResponseを返すオプション
};
const response = UrlFetchApp.fetch(url, params); // HTTPResponse
const json = response.getContentText(); // HTTPResponseの内容の文字列 = JSON文字列
const obj = JSON.parse(json); // JSON文字列をJSONオブジェクトにparse(解析)
console.log(obj.id);
}
単にユーザー情報を取得するサンプルスクリプトの最後のログ出力部分をobj.idとしてUser IDだけを確認しています。
これをgetUserId_()のような関数化してもよいのですが、User IDは固定なので、一度ログ出力して確認したら、その値をプロパティストアに格納して次回以降はプロパティストアから参照するようにします。
ということで、先程のコードの最終行を
PropertiesService.getUserProperties().setProperty('CLOCKIFY_USER_ID', obj.id);
に書き換えて完成です。
ということで、User IDをプロパティストアに格納するスクリプトの全体は以下のようになります。
function setUserId2Property() {
const apiKey = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_API_KEY'); // API Keyはプロパティストアに格納
const url = 'https://api.clockify.me/api/v1/user'; // Userのエンドポイント
/* Class UrlFetchApp のリファレンスからfetch(url, params)メソッドを確認しパラメーターの書き方を読み替える */
const params = {
contentType: 'application/json',
headers: { 'X-Api-Key': apiKey },
muteHttpExceptions: false // レスポンスが失敗した場合でもエラーを出さずにHTTPResponseを返すオプション
};
const response = UrlFetchApp.fetch(url, params); // HTTPResponse
const json = response.getContentText(); // HTTPResponseの内容の文字列 = JSON文字列
const obj = JSON.parse(json); // JSON文字列をJSONオブジェクトにparse(解析)
// console.log(obj.id);
PropertiesService.getScriptProperties().setProperty('CLOCKIFY_USER_ID', obj.id);
}
この関数を実行するとスクリプトプロパティにUser IDが格納されます。
スクリプトプロパティはGASのエディタの左側の歯車マークを押して見れるプロジェクトの設定でも確認できます。
Workspace IDを取得する
続いてWorkspace IDを同様の手順で取得したいと思います。またまた公式ドキュメントからWorkspaceのエンドポイントを確認します。
こちらもシンプルですね。先程のリクエストURLの一部だけを変えてログ出力してみます。
const url = 'https://api.clockify.me/api/v1/workspace';
ところが…
あれエラー?が出てしまいました。
※ 余談ですが、GASでAPIにリクエストを送る際のmuteHttpExceptionsはfalseにしていることが多いです。特にこだわりがあるわけでなはいですがtrueにしているとエラーが発生しないでとりあえずスクリプトが走りつづけるので、事前にエラー時の分岐(エラー処理)をしっかりと準備しておかなければいけません。これが少し面倒なためです(利用者が増えてきたら検討)。ただ、今回のようにログ出力してリクエストが成功するかを確認する段階ではtrueにしてエラー全文を確認してデバックするのは有効だと思います。
ということで、今回のエラーはエンドポイントが間違っていました。
const url = 'https://api.clockify.me/api/v1/workspaces';
workspaceに漏れていた複数形の-sを追加して無事成功しました。
すべてのWorkspaceをログ出力するスクリプトはこちらです。
function logAryWorkspaceObj() {
const apiKey = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_API_KEY'); // API Keyはプロパティストアに格納
const url = 'https://api.clockify.me/api/v1/workspaces'; // Workspaceのエンドポイント
/* Class UrlFetchApp のリファレンスからfetch(url, params)メソッドを確認しパラメーターの書き方を読み替える */
const params = {
contentType: 'application/json',
headers: { 'X-Api-Key': apiKey },
muteHttpExceptions: true // レスポンスが失敗した場合でもエラーを出さずにHTTPResponseを返すオプション
};
const response = UrlFetchApp.fetch(url, params); // HTTPResponse
const json = response.getContentText(); // HTTPResponseの内容の文字列 = JSON文字列
const workspaces = JSON.parse(json); // JSON文字列をJSONオブジェクトにparse(解析)
console.log(workspaces);
}
必要なWorkspace IDですが、Userオブジェクト同様に個々のWorkspaceオブジェクトのidプロパティに格納されているので、setUserId2Property()関数を書き換えてプロパティストアに格納してみます。
と、そのままリクエストURLをuser > workspacesに書き換えただけだと、またエラーが出ました。
ということで、公式ドキュメントのレスポンスのサンプルを確認してみたところ、戻り値は単体のオブジェクトでなく配列になっていました。
Get all my workspaces(自分のワークスペースをすべて取得する)だから当然ですよね。
とりあえず今回は、Workspaceは1つしかない前提なので、配列のインデックス0の要素にあるオブジェクトからIDを取得します。複数のWorkspaceがある方はnameプロパティなどで条件分岐してあげてください。
ということで無事完了。
Workspace IDをプロパティストアに格納するスクリプトは以下の通りです。
function setWorkspaceId2Property() {
const apiKey = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_API_KEY'); // API Keyはプロパティストアに格納
const url = 'https://api.clockify.me/api/v1/workspaces'; // Workspaceのエンドポイント
/* Class UrlFetchApp のリファレンスからfetch(url, params)メソッドを確認しパラメーターの書き方を読み替える */
const params = {
contentType: 'application/json',
headers: { 'X-Api-Key': apiKey },
muteHttpExceptions: true // レスポンスが失敗した場合でもエラーを出さずにHTTPResponseを返すオプション
};
const response = UrlFetchApp.fetch(url, params); // HTTPResponse
const json = response.getContentText(); // HTTPResponseの内容の文字列 = JSON文字列
const aryObj = JSON.parse(json); // JSON文字列をJSONオブジェクトにparse(解析)
const obj = aryObj[0]; // Workspaceが1つしかない前提なのでインデックス0を指定
PropertiesService.getScriptProperties().setProperty('CLOCKIFY_WORKSPACE_ID', obj.id);
}
おわりに
APIを触る時には、今回の記事のように公式ドキュメントとログ出力の結果を交互に確認しながらステップ・バイ・ステップで進めていくのがノンプログラマーにとっての王道だと思います。
いくつかのデータ種別でレスポンスの取得が確認できれば、他のデータ種別もスムーズに操作ができるようになります。
ということで今回はUser IDとWorkspace IDを取得してプロパティストアに格納するところまで完了しました。
シリーズ目次
- タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その1 – APIの認証を通してサンプルリクエストを送る
- タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その2 – UserとWorkspaceのIDを取得する
- タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その3 – クエリパラメータを指定して前日のエントリのみを取得する
- タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その4 – タイムエントリからカレンダーの予定を作成する
Google Apps Scriptを勉強したい方へ
この記事を見て、GASを勉強したいなと思われた方はぜひノンプログラマーのためのスキルアップ研究会(通称 ノンプロ研)にご参加ください。私も未経験からこの学習コミュニティに参加し、講座を受講したことでGASが書けるようになりました。
学習コミュニティ「ノンプログラマーのためのスキルアップ研究会」
挫折しがちなプログラミングの学習も、コミュニティの力で継続できます。ノンプロ研でお待ちしております!