Trello REST APIを使用して複数タスクを一括登録する

f:id:hamo2020:20200509102737j:plain

マネックス証券 システム開発部のHです。

はじめに

私は日常ToDo管理にTrelloを使用しているのですが、複数のタスクを一括登録できると便利かと思ったので、ツールを作成してみました。

Trelloのボード

次のようなボードがあり「MyList」というリストがあります。ここにカード(タスク)を追加していきます。 f:id:hamo2020:20200508155814p:plain

やりたいこと

下表のような複数のタスク(CSVファイル)をTrelloのREST APIを使用して一括登録します。 Linuxやcygwinなどでシェルスクリプトを作成して、内部でcURLを使ってリクエスト送信(API実行)をすると簡単にできるかと思いますが、今回はJavaを使用します。 f:id:hamo2020:20200509103420p:plain

Trello REST APIについて

Trello REST APIについては、下記にリファレンスがあります。 developer.atlassian.com

ただAPIを利用するには、API KeyとAPI Tokenを取得する必要があります。 解説ページがいろいろあるので、そちらを参考にして取得しました。

blog.serverworks.co.jp qiita.com developer.atlassian.com

今回はAPIの中から「Create a new Card」を使用します。 これはその名の通り、1つのカードを作成します。 クエリパラメータとして渡すものは下記の通りです。

クエリパラメータ 説明
API Key APIキー
API Token APIトークン
name カードのタイトル
desc 説明
due 期限
idList リストのID

「Create a new Card」を使用するにあたり、リスト(MyList)のIDも必要となるのですが、上記のリンク先などにも取得方法の記載があるので、今回は割愛します。

処理の流れ

処理については、このシーケンス図のようにCSVからタスクを読み込んで、タスク数分Trelloへ「Create a new Card」のリクエスト送信を行い、レスポンスを表示するといったごくシンプルな作りにします。 f:id:hamo2020:20200508150844p:plain

1. CSVファイルから読み込む

CSVから読み込んだタスクをリストに格納します。 CSVからタスクを読み込むにあたり、読み込んだデータを保持するDTO(Data Transfer Object)的なオブジェクトをCardという名前で定義します。 「Create a new Card」のクエリパラメータ(name、desc、due)とCSVの項目(タイトル、説明、期限)をマッピングさせます。

クエリパラメータ 説明 CSVの項目
API Key APIキー なし(固定)
API Token APIトークン なし(固定)
name カードのタイトル タイトル
desc 説明 やること
due 期限 期限
idList リストのID なし(固定)

f:id:hamo2020:20200509130345p:plain

こんな感じでCSVの内容をリストに格納します。

  1. private List<Card> getCardsFromCsv(String filename) throws IOException {
  2. return Files.lines(Path.of(filename), Charset.forName("MS932"))
  3. .filter(s -> !s.startsWith("タイトル"))
  4. .collect(ArrayList<Card>::new,
  5. (t, s) -> t.add(new Card(s)),
  6. (t, u) -> t.addAll(u));
  7. }

2. リクエストの作成

Trelloへリクエストを送信するためのHTTPクライアントは、OkHttpを使用します。 square.github.io リクエストは次のように作成します。

  1. MediaType MIMEType= MediaType.parse("text/plain; charset=sjis");
  2. RequestBody requestBody = RequestBody.create("", MIMEType);
  3. Request req = new Request.Builder()
  4. .url(createUrl(card))
  5. .post(requestBody) // メソッドはPOSTを指定
  6. .build();

createUrl()ではクエリ文パラメータを付与したURL(HttpUrl)のオブジェクトを作成します。

  1. private HttpUrl createUrl(Card card) {
  2. HttpUrl url = new HttpUrl.Builder()
  3. .scheme(conf.getScheme())
  4. .host(conf.getHost())
  5. .addPathSegments(conf.getUrlCreateANewCard())
  6. .addQueryParameter(API_KEY, conf.getKey())
  7. .addQueryParameter(API_TOKEN, conf.getToken())
  8. .addQueryParameter("name", card.getName())
  9. .addQueryParameter("desc", card.getDesc())
  10. .addQueryParameter("due", card.getDue())
  11. .addQueryParameter("idList", conf.getListId())
  12. .build();
  13. return url;
  14. }

3. Trelloへリクエスト送信(Create a new Card)、4. レスポンス

Trelloへリクエスト送信は次のようにOkHttpClientのオブジェクトを作成し、newCall().execute()のメソッドチェーンで行います。

  1. OkHttpClient client = new OkHttpClient()
  2. .newBuilder()
  3. .proxy(proxy)
  4. .build();
  5. try (Response res = client
  6. .newCall(req)
  7. .execute()) {
  8. System.out.println(res.body().string());
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. }

5. レスポンスの表示

Trelloから受信したレスポンスはこのようになります。 name、desc、dueにリクエストで指定した値が設定されています。
※dueについては、UTCでの表記のため、日本時間から9時間マイナスとなっています。

  1. {
  2. "id": "XXXXXXXXXXXXXXXXXXXXXXXX",
  3. "checkItemStates": [],
  4. "closed": false,
  5. "dateLastActivity": "2020-05-08T09:07:58.499Z",
  6. "desc": "交通費について申請する",
  7. "descData": {
  8. "emoji": {}
  9. },
  10. "dueReminder": null,
  11. "idBoard": "XXXXXXXXXXXXXXXXXXXXXXXX",
  12. "idList": "XXXXXXXXXXXXXXXXXXXXXXXX",
  13. "idMembersVoted": [],
  14. "idShort": 60,
  15. "idAttachmentCover": null,
  16. "idLabels": [],
  17. "manualCoverAttachment": false,
  18. "name": "経費精算",
  19. "pos": 163839,
  20. "shortLink": "XXXXXXXX",
  21. "isTemplate": false,
  22. "dueComplete": false,
  23. "due": "2020-05-15T08:00:00.000Z",
  24. "email": null,
  25. "labels": [],
  26. "shortUrl": "https://trello.com/c/XXXXXXXX",
  27. "url": "https://trello.com/c/XXXXXXXX/60-%E7%B5%8C%E8%B2%BB%E7%B2%BE%E7%AE%97",
  28. "cover": {
  29. "idAttachment": null,
  30. "color": null,
  31. "idUploadedBackground": null,
  32. "size": "normal",
  33. "brightness": "light"
  34. },
  35. "idMembers": [],
  36. "attachments": [],
  37. "badges": {
  38. "attachmentsByType": {
  39. "trello": {
  40. "board": 0,
  41. "card": 0
  42. }
  43. },
  44. "location": false,
  45. "votes": 0,
  46. "viewingMemberVoted": false,
  47. "subscribed": false,
  48. "fogbugz": "",
  49. "checkItems": 0,
  50. "checkItemsChecked": 0,
  51. "checkItemsEarliestDue": null,
  52. "comments": 0,
  53. "attachments": 0,
  54. "description": true,
  55. "due": "2020-05-15T08:00:00.000Z",
  56. "dueComplete": false
  57. },
  58. "subscribed": false,
  59. "idChecklists": [],
  60. "stickers": [],
  61. "limits": {}
  62. }

複数タスクの一括登録

上記の2~5は1つのタスクについての処理だったので、これを複数タスクの一括登録にすると、次のようになります。

  1. private void sendRequests(List<Card> cards) throws IOException {
  2. SocketAddress addr = new InetSocketAddress(
  3. conf.getProxyHost(), conf.getProxyPort());
  4. Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
  5. OkHttpClient client = new OkHttpClient()
  6. .newBuilder()
  7. .proxy(proxy)
  8. .build();
  9. cards.stream()
  10. .forEach(c -> sendRequest(c, client));
  11. }
  12. private void sendRequest(Card card, OkHttpClient client) {
  13. MediaType MIMEType= MediaType.parse("text/plain; charset=sjis");
  14. RequestBody requestBody = RequestBody.create("", MIMEType);
  15. Request req = new Request.Builder()
  16. .url(createUrl(card))
  17. .post(requestBody)
  18. .build();
  19. try (Response res = client
  20. .newCall(req)
  21. .execute()) {
  22. System.out.println(res.body().string());
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. }

Trelloの画面上ではMyListに4つのカードが追加されています。 f:id:hamo2020:20200508183618p:plain

説明、期限についてもリクエストで指定したものが設定されています。 f:id:hamo2020:20200509143919p:plain

おわりに

Trello REST APIやOkHttpについては、関連する記事がいろいろあるので、特に大きな壁にぶつかることもなく、複数タスクの一括登録を実現することができました。