マネックス証券 システム開発部の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については、関連する記事がいろいろあるので、特に大きな壁にぶつかることもなく、複数タスクの一括登録を実現することができました。