どうも。つじけ(tsujikenzo)です。このシリーズでは、「会計freeeAPIクラスを作ろう」について、全3回でお送りいたします。今日は2回目です。
前回のおさらい
前回は、「認証を楽にしよう」をお届けしました。
今回は、「クラスで楽をしよう」をお届けします。
今日のアジェンダ
- なぜクラスで書くのか
- 会計freeeAPIとクラス
- 処理のクラス化
- クラスの使い方
なぜクラスで書くのか
「クラスとはなにか?」とは、プログラミングにおいて永遠のテーマです。
その文脈、場面、状況によって、さまざま言い換えることができます。
今回、会計freeeAPIをクラスで書く理由は、「どこになにが書いてあるかわかりやすくして後で読むときに楽したい」 からです。
GASでやりたいこと
会計freeeAPIをGASで操作してやりたいことは、たっくさんあります。
- 口座明細を取得したい
- 請求書を発行したい
- 取引明細の中から、入金日が近いものを抽出したい
しかしながら、このようなことを実現するために、書かないといけないコードがたっくさんあります。
- アクセストークンを取得する
- 取引先一覧から取引先IDを確認する
- スプレッドシートに出力する
業務ごとに、あちこちに散らばったコードを管理するのは大変です。
「共通する処理はまとめる」、「書く場所を統一する」、というのがクラス化の基本です。
会計freeeAPIとクラス
クラスを書くときの悩みどころとして 「すべての機能を書くべきか」 があります。
ブラウザを活用しよう
たとえば、「取引先IDを確認したい」という場面です。
freeeデータベースから情報を取得するさい、パラメータには「取引先名」ではなく「partner_id」を指定する必要があります。
しかし、プログラミングするのは手間がかかります。ブラウザで確認したほうが早いです。
取引(収入/支出)の中から、条件に一致するレコードを抽出したいばめんもあります。
しかし、検索条件のパラメータを、すべてプログラミングで書くのは大変です。
ブラウザには、人間の目にやさしい、使いやすいインターフェイスが用意されています。
「ある指定条件に一致する取引を、スプレッドシートに流し込んで、PDFにしたい!」ということはあると思いますが、少し立ち止まって 「それって、ブラウザでいいんじゃないの?」 という視点を持つことも重要です。個人的に、結構重要だと思います。
freeeは、データの「csv取り込み」も用意してくれています。すべて自動化しよう、と考えずに、すでに用意されているツールはうまく活用していきましょう。
会計freeeAPIとクラス
そんなことをいうと、元も子もありませんが、そもそも会計freeeは「クラス」で成り立っています。※個人の感想です
クラウド上にあるソフトウェアは、データベースと連携して、さまざまな機能を提供しています。
わたしたちは、わざわざプログラミングなんかしなくても、freeeが用意してくれているインターフェイス(ブラウザ)を操作するだけで、経理業務ができるのです。
なので、もし、わたしたちがプログラミング(処理のクラス化)をするなら、その意向に沿うべきです。
その意向がとくに現れているのが、公式リファレンス(正式名称、会計APIリファレンス)です。
アクセスするデータ種別ごとに、アルファベット順にならんでおり、操作(DELETE、GET、POST、PUT)に関する情報が記載されています。
なので、今回は、クラスを以下のような構成にしてみます。
- APIリクエストに関するクラス
- データ種別ごと(CompaniesやDealsなど)のクラス
- その他のクラス(パラメータの作成やアクセストークン取得)
クラス図はむずかしそうで、見よう見まねで書いてみました。徐々になれていきたいと思います。
もちろん、後で変更する可能性も大です。変更を楽にしようというのがクラス化のメリットです。
処理のクラス化
最上級のクラス
会計APIリファレンスの冒頭には、APIエンドポイントや、認証についてなど、共通項目が記載されています。
たとえば、ベースとなるエンドポイントURLは決まっています。これは、どんな処理でも使い回すURLになるでしょう。
その他には、HTTPリクエストを送信するさいのparamsも、共通コードがあると思います。
そのような情報をもったクラスを、最上級のクラスに設定します。(”最上級”という意味は後ほどご説明します)
遊び心で、会計APIリクエストのURLを返すメソッドを定義しました。
/**
* ApiRequestに関するクラス
*/
class ApiRequests {
constructor() {
this.accessToken = new AccessToken().getMyAccessToken();
this.baseUrl = 'https://api.freee.co.jp/api/1/';
this.params = {
headers: { Authorization: `Bearer ${this.accessToken}` },
method: 'get'
}
this.postParams = {
contentType: 'application/json',
headers: { Authorization: `Bearer ${this.accessToken}` },
method: 'post',
payload: '',
muteHttpExceptions: false
}
}
/** 会計freeeAPIリファレンスを取得するメソッド */
getReference() {
return 'https://developer.freee.co.jp/docs/accounting/reference';
}
/**
* レスポンスのJSONをオブジェクトで返すメソッド
* @param {string} url
* @param {string} params
* @return {Objext} JSONオブジェクト
*/
fetchRequest(url, params) {
const response = UrlFetchApp.fetch(url, params).getContentText();
return JSON.parse(response);
}
}
サブクラス
個別のデータ種別をみていきましょう。
事業所の情報を操作するのは、Comapaniesです。2種類のGETが提供されているようです。
CompaniesのリクエストURLはこうです。
つまり、リクエストURLは、最上級のクラスで定義したbaseUrl+companiesということです。
最上級のクラスで定義したインスタンス変数やメソッドを使い回すために、クラスの継承(extends)を行います。
継承先のクラスでsuper()宣言をすることで、継承元のインスタンス変数を引き継ぎます。
class Companies extends ApiRequests {
/** urlを作るコンストラクタ */
constructor() {
super(); //インスタンス変数を引き継ぐ命令文
this.url = `${this.baseUrl}companies`;
}
}
以降、継承元のクラスをスーパークラス(親クラスとも呼びます)、継承先のクラスをサブクラス(子クラスとも呼びます)と呼びます。
スーパークラスに定義されているurlやparamsやfetchRequest()メソッドを使い回しながら、Companiesに必要な処理を記述していきます。
完成したのがこちらです。もちろん、機能を追加したり、変更も可能です。
/**
* 事業所に関するクラス
* @extends {ApiRequests}
*/
class Companies extends ApiRequests {
/** urlを作るコンストラクタ */
constructor() {
super();
this.url = `${this.baseUrl}companies`;
}
/**
* 事業所idと事業所名を配列で取得するメソッド
* @return {Array} companies [{id,name},{id,name}]
*/
getCompanies() {
const allCompanies = this.fetchRequest(this.url, this.params); //{}
const companiesArray = allCompanies.companies; //[]
return companiesArray;
}
/**
* 事業所名(部分一致)からidを返すメソッド
* @param {string} name - 事業所名の一部
* @return {string} id - 012345
*/
getCompaniesId(name) {
const companies = this.getCompanies();
const reg = new RegExp(name);
const filter = companies.filter(company => reg.test(company.display_name))[0]; //常に1件しかヒットしない想定
return filter.id;
}
}
クラスの使い方
いまの時点では、クラスを呼び出す処理を関数にしたり、まとめる必要はないと思います。
テスト関数などを用意して、実際に値が取得できるか確認しておきましょう。
わたしは、スクリプトファイル[99_test]を作成しました。
/** TEST用関数 */
function testCompanies() {
const c = new Companies();
console.log(c.getCompanies());
/*
[ { id: 3293428,
name: '',
name_kana: '',
display_name: '開発用テスト事業所(法人・ベーシック)',
role: 'admin' } ]
*/
console.log(c.getCompaniesId('法人・ベーシック')); //3293428
}
まとめ
以上で、「クラスで楽をしよう」をお届けしました。
クラスとは、「共通処理をまとめたもの」というイメージもあるかと思います。
しかし、共通処理だけなら、関数でもよさそうです。
もう一歩踏み込んでクラスを活用するなら、「同じ業務なら同じ場所に書こう」 という考え方をもってみましょう。
Companiesに関することはCompaniesクラスに、ApiRequestのことはApiRequestクラスに書かれていれば、後でコードを読むときも楽になります。
次回は、 「スプレッドシートで楽をしよう」 をお届けします。