マネックス証券 システム開発部のHです。
はじめに
私は日常ToDo管理にTrelloを使用しているのですが、複数のタスクを一括登録できると便利かと思ったので、ツールを作成してみました。
Trelloのボード
次のようなボードがあり「MyList」というリストがあります。ここにカード(タスク)を追加していきます。
やりたいこと
下表のような複数のタスク(CSVファイル)をTrelloのREST APIを使用して一括登録します。 Linuxやcygwinなどでシェルスクリプトを作成して、内部でcURLを使ってリクエスト送信(API実行)をすると簡単にできるかと思いますが、今回はJavaを使用します。
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」のリクエスト送信を行い、レスポンスを表示するといったごくシンプルな作りにします。
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 | なし(固定) |
こんな感じでCSVの内容をリストに格納します。
private List<Card> getCardsFromCsv(String filename) throws IOException { return Files.lines(Path.of(filename), Charset.forName("MS932")) .filter(s -> !s.startsWith("タイトル")) .collect(ArrayList<Card>::new, (t, s) -> t.add(new Card(s)), (t, u) -> t.addAll(u)); }
2. リクエストの作成
Trelloへリクエストを送信するためのHTTPクライアントは、OkHttpを使用します。 square.github.io リクエストは次のように作成します。
MediaType MIMEType= MediaType.parse("text/plain; charset=sjis"); RequestBody requestBody = RequestBody.create("", MIMEType); Request req = new Request.Builder() .url(createUrl(card)) .post(requestBody) // メソッドはPOSTを指定 .build();
createUrl()ではクエリ文パラメータを付与したURL(HttpUrl)のオブジェクトを作成します。
private HttpUrl createUrl(Card card) { HttpUrl url = new HttpUrl.Builder() .scheme(conf.getScheme()) .host(conf.getHost()) .addPathSegments(conf.getUrlCreateANewCard()) .addQueryParameter(API_KEY, conf.getKey()) .addQueryParameter(API_TOKEN, conf.getToken()) .addQueryParameter("name", card.getName()) .addQueryParameter("desc", card.getDesc()) .addQueryParameter("due", card.getDue()) .addQueryParameter("idList", conf.getListId()) .build(); return url; }
3. Trelloへリクエスト送信(Create a new Card)、4. レスポンス
Trelloへリクエスト送信は次のようにOkHttpClientのオブジェクトを作成し、newCall().execute()のメソッドチェーンで行います。
OkHttpClient client = new OkHttpClient() .newBuilder() .proxy(proxy) .build(); try (Response res = client .newCall(req) .execute()) { System.out.println(res.body().string()); } catch (IOException e) { e.printStackTrace(); }
5. レスポンスの表示
Trelloから受信したレスポンスはこのようになります。
name、desc、dueにリクエストで指定した値が設定されています。
※dueについては、UTCでの表記のため、日本時間から9時間マイナスとなっています。
{ "id": "XXXXXXXXXXXXXXXXXXXXXXXX", "checkItemStates": [], "closed": false, "dateLastActivity": "2020-05-08T09:07:58.499Z", "desc": "交通費について申請する", "descData": { "emoji": {} }, "dueReminder": null, "idBoard": "XXXXXXXXXXXXXXXXXXXXXXXX", "idList": "XXXXXXXXXXXXXXXXXXXXXXXX", "idMembersVoted": [], "idShort": 60, "idAttachmentCover": null, "idLabels": [], "manualCoverAttachment": false, "name": "経費精算", "pos": 163839, "shortLink": "XXXXXXXX", "isTemplate": false, "dueComplete": false, "due": "2020-05-15T08:00:00.000Z", "email": null, "labels": [], "shortUrl": "https://trello.com/c/XXXXXXXX", "url": "https://trello.com/c/XXXXXXXX/60-%E7%B5%8C%E8%B2%BB%E7%B2%BE%E7%AE%97", "cover": { "idAttachment": null, "color": null, "idUploadedBackground": null, "size": "normal", "brightness": "light" }, "idMembers": [], "attachments": [], "badges": { "attachmentsByType": { "trello": { "board": 0, "card": 0 } }, "location": false, "votes": 0, "viewingMemberVoted": false, "subscribed": false, "fogbugz": "", "checkItems": 0, "checkItemsChecked": 0, "checkItemsEarliestDue": null, "comments": 0, "attachments": 0, "description": true, "due": "2020-05-15T08:00:00.000Z", "dueComplete": false }, "subscribed": false, "idChecklists": [], "stickers": [], "limits": {} }
複数タスクの一括登録
上記の2~5は1つのタスクについての処理だったので、これを複数タスクの一括登録にすると、次のようになります。
private void sendRequests(List<Card> cards) throws IOException { SocketAddress addr = new InetSocketAddress( conf.getProxyHost(), conf.getProxyPort()); Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); OkHttpClient client = new OkHttpClient() .newBuilder() .proxy(proxy) .build(); cards.stream() .forEach(c -> sendRequest(c, client)); } private void sendRequest(Card card, OkHttpClient client) { MediaType MIMEType= MediaType.parse("text/plain; charset=sjis"); RequestBody requestBody = RequestBody.create("", MIMEType); Request req = new Request.Builder() .url(createUrl(card)) .post(requestBody) .build(); try (Response res = client .newCall(req) .execute()) { System.out.println(res.body().string()); } catch (IOException e) { e.printStackTrace(); } }
Trelloの画面上ではMyListに4つのカードが追加されています。
説明、期限についてもリクエストで指定したものが設定されています。
おわりに
Trello REST APIやOkHttpについては、関連する記事がいろいろあるので、特に大きな壁にぶつかることもなく、複数タスクの一括登録を実現することができました。