どうも。つじけ(tsujikenzo)です。このシリーズでは、「会計freeeAPIクラスを作ろう」について、全3回でお送りいたします。今日は1回目です。
このシリーズは、2021年9月から開催されていた「ノンプロ研freeeAPI講座1期卒業LT」の登壇資料です。
シリーズ全体を通して言えることですが、プログラミングにおいて、クラスはこれがぜったい正しいという書き方がないものだと思っています。
クラスは、プログラミングの何かを楽にする技術です。
プログラミングスキルや、現在抱えてる課題によって、楽にしたいことは変化します。
なので、明日には真逆のことを言っている可能性もあります。予めご了承ください。
このシリーズのアジェンダ
- 認証を楽にしよう
- クラスで楽をしよう
- スプレッドシートで楽をしよう
今日は1回目で、「認証を楽にしよう」をお届けします。
今日のアジェンダ
- プロパティストア
- 認証
- アクセストークン
会計freeeAPIクラスで認証を極めるコツは、開発用テスト環境でなんども作成、認証、削除を繰り返し、認証を通すことに慣れることです。
「よくわからないけど、一回認証通ったからいいか」という感じだと、後で認証が切れたときに「あれ、認証ってどうやってたっけ」という状況になります。(わたし自身、何度も経験があります)
この回では、2度と認証でつまづかない環境を作っていきます。
プロパティストア
コンテナバインドスクリプト
まず、大前提として、このクラスは、コンテナバインドスクリプトで作成します。
スタンドアロンスクリプトで読み替えるスキルのある方は、そのままお進みください。
コンテナバインドスクリプト内に、スクリプトファイル[00_setUserProperties]を作成します。
コールバックURL
マイアプリには、コールバックURLの指定が必要です。
スクリプトファイル[00_setUserProperties]に、以下を記述しておきます。
このように、必要なメモはファイル内に記述しておきましょう。
/** マイアプリのコールバックURL */
//https://script.google.com/macros/d/スクリプトID/usercallback
プロパティストアに格納
マイアプリで表示されているCLIENT_IDとCLIENT_SECRETを、ユーザープロパティストアに格納します。
スクリプトプロパティストアでもかまいません。
グローバル領域では、定数に格納してプロジェクト全体からアクセスできるようにしておきます。
一度プロパティストアに格納したら、ベタ書きしているIDとSECRETは削除してかまいません。
完成したスクリプトファイル[00_setUserProperties]はこちらです。
/** マイアプリのコールバックURL */
//https://script.google.com/macros/d/スクリプトID/usercallback
/** プロパティストアに格納 */
function setClientIdAndSecret() {
//プロパティストアを空にしておく
PropertiesService.getScriptProperties().deleteAllProperties();
PropertiesService.getUserProperties().deleteAllProperties();
PropertiesService.getDocumentProperties().deleteAllProperties();
//マイアプリ情報
const CLIENT_ID = '';
const CLIENT_SECRET = '';
//userPropertiesに格納する
const userProperties = PropertiesService.getUserProperties();
userProperties.setProperty('CLIENT_ID', CLIENT_ID);
userProperties.setProperty('CLIENT_SECRET', CLIENT_SECRET);
console.log(userProperties.getProperties());
}
const CLIENT_ID = PropertiesService.getUserProperties().getProperty('CLIENT_ID');
const CLIENT_SECRET = PropertiesService.getUserProperties().getProperty('CLIENT_SECRET');
認証
alertAuth()関数の作成
続いて、スクリプトファイル[01_firstAuthorization]を作成します。
初回実行時や、コードを走らせると「ログインしてください」エラーが出るときは、アクセストークンの認証が切れているときです。
都度、下記のalertAuth()関数を実行しましょう。
冒頭部分で、記述する注意事項はこちらです。
/** コンテナバインドスクリプトで実行していますか? */
//
/** OAuth2.0ライブラリはインストールしましたか? */
// 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
/** 00_setProperties.gsは実行しましたか? */
//setClientIdAndSecret()
/** 初回、および認証が切れているときに実行する */
//実行ログに「実行完了」が表示されたらスプレッドシートを確認します
alertAuth()関数はこちらです。
公式サイトで紹介されているコードに、少しアレンジを加えています。
変数freeeOAuthObjectで設定している項目を削ったりすると動かなくなります。そのままコピペしてください。
認証コールバック関数用のサブ関数も、同じスクリプトファイル内に記述しておきます。
function alertAuth() {
const freeeOAuthObject = OAuth2.createService('freee')
.setAuthorizationBaseUrl('https://accounts.secure.freee.co.jp/public_api/authorize')
.setTokenUrl('https://accounts.secure.freee.co.jp/public_api/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback_')
.setPropertyStore(PropertiesService.getUserProperties());
const authorizationUrl = freeeOAuthObject.getAuthorizationUrl();
const template = HtmlService.createTemplate(
'<a href="<?= authorizationUrl ?>" target="_blank">認証</a>. ' +
'こちらをクリックすると表示される新しいウィンドウで「許可する」をクリックしてください。');
template.authorizationUrl = authorizationUrl;
const page = template.evaluate();
SpreadsheetApp.getUi().showModalDialog(page, "認証をしてください");
console.log('スプレッドシートを開く');
}
//認証コールバック関数
function authCallback_(request) {
const service = OAuth2.createService('freee')
.setAuthorizationBaseUrl('https://accounts.secure.freee.co.jp/public_api/authorize')
.setTokenUrl('https://accounts.secure.freee.co.jp/public_api/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback_')
.setPropertyStore(PropertiesService.getUserProperties());
const isAuthorized = service.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('認証に成功しました。タブを閉じてください。');
} else {
return HtmlService.createHtmlOutput('認証に失敗しました。');
};
}
alertAuth()関数の実行
実行は手動です。
実行すると、ログに「スプレッドシートを開く」と表示されます。スプレッドシートをクリックしましょう。
このような画面が表示されます。[認証]をクリックします。
別タブが開いて、アプリ連携の開始画面が表示されます。※ログインを求められるばあいもあります。
「許可する」をクリックします。
認証に成功すると、このような表示がでますので、タブを閉じます。スプレッドシートの認証ウィンドウも閉じます。
alertAuth()関数はいつでも実行してかまいません。認証を上書きしても問題ありませんので、何度も実行してみましょう。
関数を実行すると、Exception: Cannot call SpreadsheetApp.getUi() from this context. というエラーが出るときは、一度スクリプトエディタを閉じて、再度、スプレッドシートからコンテナバインドスクリプトを開きましょう。
アクセストークン
クラスAccessToken
アクセストークンの取得はクラス化します。
スクリプトファイル[class_AccessToken]を作成します。
インスタンス変数を2つ、メソッドを2つ記述します。
こちらもコピペでかまいません。
/**
* freeeAPIOauthに関するクラス
*/
class AccessToken {
/**
* clientId,clientSecretプロパティを定義するコンストラクタ
* @constructor
*/
constructor() {
this.clientId = CLIENT_ID;
this.clientSecret = CLIENT_SECRET;
}
/**
* アクセストークンを取得するメソッド
* @return {string} アクセストークン
*/
getMyAccessToken() {
return this.getService_().getAccessToken();
}
/**
* OAuth2ライブラリからオブジェクトを取得するメソッド
* @return {Object} freeeOAuthオブジェクト
*/
getService_() {
return OAuth2.createService('freee')
.setAuthorizationBaseUrl('https://accounts.secure.freee.co.jp/public_api/authorize')
.setTokenUrl('https://accounts.secure.freee.co.jp/public_api/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties());
}
}
アクセストークン確認用関数
最後に、アクセストークンが取れるか、確認するための関数を用意しておきます。
スクリプトファイル[02_checkMyAccessToken]を作成します。
checkMyAccessToken()関数を手動で実行すると、アクセストークンを確認できます。
/** アクセストークン確認用 */
function checkMyAccessToken() {
const a = new AccessToken();
console.log(a.getMyAccessToken());
//hogehogeac5d362fc0c2911c636c44cb38483de03d3755f2acaaadfd
}
セキュリティの都合上、アクセストークンの有効期限は24時間になっています。有効期限内であればリフレッシュトークンを利用し、アクセストークンの再取得ができます。
アクセストークンの有効期限が切れたばあいは、アクセストークンを再取得する必要があり、その際に認証が必要です。
次回以降、実際にアクセストークンを取得しながら、freeeAPIを叩いていきます。
まとめ
以上で、「認証を楽にしよう」をお届けしました。
公式サイトにも記載のある認証用のコードは、認証とアクセストークン取得が一緒になっています。(逆に言うと同じ処理なので、共通化されている) 引用元:freee APIのアクセストークンを取得する
わたしの認識として、認証は1度しか行わないもので、アクセストークンの取得は頻繁に行うイメージです。
なので、認証とアクセストークンの取得を分けて、クラス化しました。
次回は、 「クラスで楽をしよう」 をお届けします。