どうも。ケニー(tsujikenzo)です。このシリーズでは「[Asana API]スプレッドシート連携でタスク登録をしよう」をお届けしています。
今日は9回目です。
前回のおさらい
前回は、「スプレッドシートクラス」をお届けしました。
クラスでプログラミングすることにも、慣れてきたのではないでしょうか。
オブジェクト指向?そんなことは考えなくていいです。どこに何が書いているのか、誰に何をやらせるのか、再利用しやすいよね、そんなプログラムを目指しています。
そもそもES6で登場したclass構文は、シンタックスシュガー(糖衣構文)であり、カプセル化や継承などをプロトタイプベー
今回は、「カスタムAsanaクラス」です。
今日のアジェンダ
- カスタムAsanaクラスの基礎
- クラスの実装
- オブジェクト指向のポイント
カスタムAsanaクラスの基礎
Asanaに関する処理をまとめ、クラス化します。
クラスの命名
わたしは、カスタマイズしたAsanaクラスという意味で「CustomAsana」と名付けてますが、AsanaManagerなどもいいでしょう。
なぜクラス名を「Asana」としないかは、後ほど説明します。
クラスの責務
カスタムAsanaクラスに、やってほしいお仕事(責務と言ったりしますが)は、以下のようなものです。
- (Asanaにタスクを登録するために、データを整形する)← postシートに任せる
- Asanaにタスクを登録する
- Asanaのタスクを更新する
- Asanaの登録・更新処理が終わったらなにかしらのメッセージを送信する
- (Asanaの各GIDを取得する)← 違うところでやる
これはまだ未実装ですが、もし、Asanaにタスクを登録するためにデータを整形するメソッドが必要になったら、postシートにやってもらいます。
必要になったら、このブログでも追記しますので。
アプリに含めない処理とユースケース図
そして、このブログの1~3回目ぐらいまでに紹介した「各IDを取得する」という処理は、どっか別のスプレッドシートでやってもらいます。
プロジェクトやメンバーなどのGIDは、そんなにコロコロ変わるものでもありません。あまりアプリを大きくしないコツです。
今回の目的は、「スプレッドシートからタスクを登録」したいのです。ユースケース図で表現するとこうなります。
このブログをハンズオンで進めてきたなら、このようなスクリプトエディタがあると思いますので、それで十分だと思います。
最終的には1つのアプリとして、クラス化して格納すると思いますが。。。
クラスの実装
ということで、カスタムAsanaクラスで担う処理は大きく分けて2つです。
- Asanaにタスクをpost(登録)する
- Asanaにタスクをput(更新)する
まずはpostから優先的に、GASを書いてみましょう。
最下部には、このクラスをテストする関数を置いています。
/** クラスCustomAsana */
class CustomAsana {
/** コンストラクタ */
constructor() {
this.accessToken = "あなたのアクセストークン";
this.workspaceId = "あなたのワークスペースGID";
}
/** タスクを登録する */
createTask(task) {
const url = 'https://app.asana.com/api/1.0/tasks';
const payload = {
data: {
workspace: this.workspaceId,
memberships: [{ project: task['project1'], section: task['section1'] }],
name: task['name'],
notes: task['notes'],
assignee: task['assignee'],
tags: task['tags'],
followers: [task['followersIds']]
}
};
const options = {
method: 'post',
contentType: 'application/json',
headers: {
'Authorization': 'Bearer ' + this.accessToken
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
const response = UrlFetchApp.fetch(url, options);
const jsonResponse = JSON.parse(response.getContentText());
console.log(jsonResponse);
} catch (e) {
console.log("Exception when calling API: " + e.toString());
}
}
}
/** テスト関数 */
function testCustomAsana() {
//CustomAsanaのインスタンス化
const a = new CustomAsana();
//タスクの登録
const task = {
project1: 'プロジェクトID',
section1: 'セクションID',
name: 'タスクの名前',
notes: 'タスクの内容',
assignee: 'me',
tags: ['あなたのタグGID','あなたのタグGID'],
followersIds: 'コレボレーターのGID'
};
a.createTask(task);
}
テスト関数を実行してみましょう。
Asanaに、タスクが登録されていれば成功です。
PUT処理(タスクの更新)については、あまり需要がないと考えて、今回のブログでは割愛します。
PUTを楽しみにされていた方には、お詫び申し上げます。
オブジェクト指向のポイント
「ケニーさん、オブジェクト指向的に書くには、どうしたらいいのでしょうか。」という質問が、過去のケニーからあったとしたら、こう答えます。
コンストラクタでタスクオブジェクトを受け取る方法
この方法は、インスタンスごとに一つのタスクを扱う場合や、クラスのインスタンスをタスクそのものとして扱いたい場合に適しています。
このアプローチを採用すると、クラスのインスタンスがタスクのライフサイクル(作成、更新など)を管理するエンティティとなります。
class CustomAsana {
/** コンストラクタ
* @param{Object} taskObject
*/
constructor(taskObject) {
this.accessToken = 'YOUR_ACCESS_TOKEN';
this.workspaceId = 'YOUR_WORKSPACE_ID';
this.name = taskObject.name;
this.notes = taskObject.notes;
// その他のプロパティも同様に初期化...
}
createTask() {
// ここで this.name, this.notes などを使用してタスクを作成
}
// タスクの更新や削除など、他のメソッドも定義可能
}
// 使用例
const taskObject = { name: "サンプルタスク", notes: "タスクの詳細" };
const task = new CustomAsana(taskObject);
task.create();
上記は、タスクとその操作をカプセル化(GASでは完璧にはカプセル化できませんが)したい場合や、オブジェクト指向設計を強調したい場合に適しています。
createTask() メソッドにタスクオブジェクトを渡す方法
この方法は、一つのクラス(またはインスタンス)が複数のタスクの作成を管理する場合に適しています。
たとえば、一連のタスクをバッチ処理で作成する場合などです。
この方法の利点は、コードがより柔軟で再利用しやすくなる点にあります。
class CustomAsana {
/** コンストラクタ
* @param{string} アクセストークン
* @param{string} ワークスペースID
*/
constructor(accessToken, workspaceId) {
this.accessToken = accessToken;
this.workspaceId = workspaceId;
}
createTask(taskObject) {
// taskObject からタスクを作成
}
}
// 使用例
const manager = new CustomAsana('YOUR_ACCESS_TOKEN', 'YOUR_WORKSPACE_ID');
const taskObjects = [
{ name: "タスク1", notes: "詳細1" },
{ name: "タスク2", notes: "詳細2" }
];
taskObjects.forEach(taskObject => manager.createTask(taskObject));
上記は、複数のタスクを効率的に処理したい場合や、タスク作成以外にも様々な操作を一つのクラスで管理したい場合に適しています。
今回は、後者を選択しました。
タスクオブジェクトをメソッドに渡していますが、あまりオブジェクト指向っぽいとは思っていません。
ただ、処理をメソッドとしてクラスに格納している、そして引数として必要な要素(オブジェクトですが)を渡して、順次処理しているに過ぎないと思っています。
まとめ
以上で、「カスタムAsanaクラス」をお送りしました。
クラス名に「カスタムAsana」と命名しているのは、Asana API自体が、クラスの集まりであり、「Asanaクラス」というには変だと思うからです。
今回は、Asana APIを便利に使いたい、使えるようになる、という意味を込めています。
次回は、最終回で「グローバルとカスタムメニューとmain」をお届けします。お楽しみに。