タスク管理ツール WunderlistのAPIで遊んでみた

  • 14
    いいね
  • 2
    コメント

こんにちは、最近は寒すぎて電気カーペットの上で直接寝てしまう木佐貫(@nori4k)です。

非エンジニアとのタスク共有にWunderlistを使っています。
機能もUIもシンプルで分かりやすいので普段はスマホくらいしか触らない人でも負担なく導入することができとても重宝しています。
WunderlistからAPIも提供されているのでどんな風につかうのか早速試してみました。

Wunderlist とは

Wunderlist は、タスク管理を支援するシンプルな ToDo リスト アプリです。家族との買い物リストの共有からプロジェクト管理、休暇の計画まで、Wunderlist を使えば、ToDo の入力、共有、そして実行を簡単に行うことができます。Wunderlist はスマートフォン、タブレット、PC の間で瞬時に同期するAため、あらゆるタスクにどこからでもアクセスできます。

(iPhoneアプリの説明欄から引用)

Wunderlistではリスト - タスク - サブタスク の3階層構造でタスクを管理する仕組みになっています。
例えば、「買い物」というリストがあり、その中に「ティッシュ」「ミルク」「醤油」「夕飯の買い出し」などのタスクを作って管理します。場合によっては「夕飯の買い出し」に更にサブタスクを作ることができます。

また、リストをカテゴリ分けするためのフォルダという機能もあります。
これは文字通りリストをフォルダ分けすることができる機能です。

APIを使うための準備

APIを利用するためにはClientIDとAccessTokenが必要です。

  1. 以下にアクセス
    https://developer.wunderlist.com/

  2. register your app をクリック

  3. Create NewAppという画面が開くので必要情報を入力
    今回は次のように入力しsaveをクリック
    Name: hoge
    Description: hogehoge
    App icon: なし
    App url: http://myapp.net
    Auth Callback url: http://myapp.net

  4. My Appという画面が開く
    ClientIDをメモする。
    Create Access TokenをクリックしてAccessTokenを生成しメモしておく。

これでAPIを使用する準備が整いました!

APIの動作確認

今回はcurlを使ってAPIの動作を見てみることにします。
詳しくは公式ドキュメントをご覧ください。

リスト一覧の取得

リスト一覧を取得してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/lists

レスポンス

[
    {
        "created_at": "2017-02-03T16:00:54.570Z", 
        "id": 289113886, 
        "list_type": "inbox", 
        "owner_id": 48481118, 
        "owner_type": "user", 
        "public": false, 
        "revision": 1, 
        "title": "inbox", 
        "type": "list"
    }, 
    {
        "created_at": "2017-02-03T16:01:05.807Z", 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lwf70ac84aecf208b6e54cb227755032", 
        "id": 289113923, 
        "list_type": "list", 
        "owner_id": 48481118, 
        "owner_type": "user", 
        "public": false, 
        "revision": 4, 
        "title": "食料品", 
        "type": "list"
    }
]

inbox食料品という2つのリストが取得できました。

フォルダ一覧の取得

フォルダ一覧を取得してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/folders

レスポンス

[
    {
        "created_at": "2017-02-03T16:12:24.161Z", 
        "created_by_id": 48481118, 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw0e0b4864b5ea8e8300b002d7f656fb", 
        "id": 6754585, 
        "list_ids": [
            289113923
        ], 
        "revision": 2, 
        "title": "Folder01", 
        "type": "folder", 
        "updated_at": "2017-02-03T16:12:29.360Z", 
        "user_id": 48481118
    }
]

タスク一覧の取得

タスク一覧を取得してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/tasks?list_id=289113923

レスポンス

[
    {
        "completed": false, 
        "created_at": "2017-02-03T16:06:02.482Z", 
        "created_by_id": 48481118, 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw9716f473956e5aa3d4e5459e3211e5", 
        "id": 2501790935, 
        "list_id": 289113923, 
        "revision": 2, 
        "starred": false, 
        "title": "タスク", 
        "type": "task"
    }
]

タスク一覧が取得できました。この例ではタスクが1つしかありませんでしたが、複数あれば配列の形で一括取得できそうです。
revisionはタスクに対して何かしらの修正が行われたときにインクリメントされるみたいです。

サブタスク一覧の取得

サブタスク一覧を取得してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/subtasks?list_id=289113923

レスポンス

[
    {
        "completed": true, 
        "completed_at": "2017-02-03T16:16:49.162Z", 
        "created_at": "2017-02-03T16:16:39.874Z", 
        "created_by_id": 48481118, 
        "created_by_request_id": "subtask:498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw332052f52407696b86632c27d0c9f1", 
        "id": 1363942139, 
        "revision": 2, 
        "task_id": 2501790935, 
        "title": "サブタスク1", 
        "type": "subtask"
    }, 
    {
        "completed": false, 
        "created_at": "2017-02-03T16:16:46.296Z", 
        "created_by_id": 48481118, 
        "created_by_request_id": "subtask:498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lwe9ed06158ac87dcd846b060d671630", 
        "id": 1363942171, 
        "revision": 1, 
        "task_id": 2501790935, 
        "title": "サブタスク3", 
        "type": "subtask"
    }, 
    {
        "completed": false, 
        "created_at": "2017-02-03T16:16:42.900Z", 
        "created_by_id": 48481118, 
        "created_by_request_id": "subtask:498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw34349df41802ba2c13f4faecfa5d18", 
        "id": 1363942150, 
        "revision": 1, 
        "task_id": 2501790935, 
        "title": "サブタスク2", 
        "type": "subtask"
    }
]

サブタスク一覧が取得できました。
list_idを指定することで、リスト内のサブタスクを一括取得できるのが便利です。
もちろんtask_idをしていすることで特定のタスク配下のサブタスクのみを取得することも可能です。

メモ一覧の取得

メモ一覧を取得してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/notes?list_id=289113923

レスポンス

[
    {
        "content": "こちらがノート", 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lwef206de86e88ab1d34ad3e39f08f7d", 
        "id": 172985213, 
        "revision": 1, 
        "task_id": 2501790935, 
        "type": "note"
    }
]

コメント一覧の取得

コメント一覧を取得してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/task_comments?list_id=289113923

レスポンス

[
    {
        "author": {
            "avatar": "https://a.wunderlist.com/api/v1/avatar?user_id=48481118", 
            "id": 48481118, 
            "name": "your name"
        }, 
        "created_at": "2017-02-03T16:13:17.000Z", 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw242a3dc76707a21b3661383e388407", 
        "id": 54718254, 
        "local_created_at": "2017-02-03T16:13:21.711Z", 
        "revision": 1, 
        "task_id": 2501790935, 
        "text": "コメントだよ", 
        "type": "task_comment"
    }
]

添付ファイル一覧の取得

添付ファイル一覧を取得してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/files?list_id=289113923

レスポンス

[
    {
        "content_type": "image/png", 
        "created_at": "2017-02-03T16:15:04.303Z", 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw7f6545b24ab8d9e4cd8bff539f903f", 
        "file_name": "SnapCrab_My Apps  Wunderlist Developer - Google Chrome_2017-2-4_1-4-55_No-00.png", 
        "file_size": 147744, 
        "id": 22489318, 
        "local_created_at": "2017-02-03T16:15:04.000Z", 
        "revision": 1, 
        "task_id": 2501790935, 
        "type": "file", 
        "updated_at": "2017-02-03T16:15:04.646Z", 
        "url": "https://download.wunderlist.io/d519bf30-cc59-0134-9abe-22000a0a0772-1486138498-834452?AWSAccessKeyId=AKIAJEN6W4AO3LJODOAA&Expires=1488557704&Signature=vr%2BPL9WLuhP8wF4gY%2FOS3uf%2BdyE%3D", 
        "user_id": 48481118
    }
]

webhookの作成

Webhookも試してみます。
Webhookを登録しておくとWunderlistに変更があった場合に変更内容の通知を受け取ることができます。
ポーリングする必要がなくなるのでWunderlistと連携したアプリ開発をするときには必須ですね。
webhookはリスト毎に設定でき、一つのリストに複数のwebhookを設定できます。

url=xxxxxxの部分にcallback URLを設定します。

curl -H "X-Access-Token: xxxxxx" \
-H "X-Client-ID: yyyyyy" \
-X POST \
-F "list_id=289113923" \
-F "url=http://myapp.net/callback.php" \
-F "processor_type=generic" \
-F "configuration=" \
a.wunderlist.com/api/v1/webhooks

callback.phpも用意しておきます。

<?php

$json_string = file_get_contents('php://input'); 
echo $json_string;
$obj = json_decode($json_string);
var_dump($obj);

レスポンス

{
    "id": 2502681, 
    "list_id": 289113923, 
    "url": "http://myapp.net/callback.php"
}

最初はコールバックURLをhttpsで指定していたのですが、wunderlist側からのアクセスがあるもののjsonを受け取ることができせんでした。SSLを諦めてhttpで指定したら無事jsonを受け取れるようになりました。
SSL化に無料で使える"Let's Encrypt"の証明書を使っていたのが悪かったのかもしれません。

webhookの取得

設定されたwebhookの情報を取得してみます。
リスト毎にしか取得できないので、全リストのwebhookを一括取得できるAPIもほしい。。。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" a.wunderlist.com/api/v1/webhooks?list_id=289113923

レスポンス

[
    {
        "id": 2502681, 
        "list_id": 289113923, 
        "url": "http://myapp.net/callback.php"
    }
]

webhookの削除

webhookを削除してみます。

curl -H "X-Access-Token: xxxxxx" -H "X-Client-ID: yyyyyy" -X DELETE a.wunderlist.com/api/v1/webhooks/2502681

レスポンス

なし

webhookを削除するには「webhookの取得」で取得したwebhookのidを指定します。
思い込みでlist_idを指定していてエラーの原因がわかるのに小一時間くらいかかりました。。。

callbackされるjson

通知はタスク / サブタスク / メモ / ファイル / コメント などの作成・更新・削除のタイミングで行われます。
リストの共有なぜか通知されなかったです。

タスクを完了させたときのjsonを参考に掲載しておきます。

{
    "after": {
        "completed": true, 
        "completed_at": "2017-02-03T22:17:06.268Z", 
        "completed_by_id": 48481118, 
        "created_at": "2017-02-03T16:06:02.482Z", 
        "created_by_id": 48481118, 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c291:f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw9716f473956e5aa3d4e5459e3211e5", 
        "id": 2501790935, 
        "is_recurrence_child": false, 
        "list_id": 289113923, 
        "revision": 41, 
        "starred": false, 
        "title": "タスク", 
        "updated_at": "2017-02-03T22:17:06.271Z", 
        "updated_by_id": 48481118
    }, 
    "before": {
        "completed": false, 
        "created_at": "2017-02-03T16:06:02.482Z", 
        "created_by_id": 48481118, 
        "created_by_request_id": "498d3ffc44ddfa2f275b:92840a96-1d01-463c-956b-dff9594c2941:f43d7f5-5be5-45b1-a70c-b3a9-7dc9583d:48481118:lw9716f473956e5aa3d4e5459e3211e5", 
        "id": 2501790935, 
        "is_recurrence_child": false, 
        "list_id": 289113923, 
        "revision": 40, 
        "starred": false, 
        "title": "タスク", 
        "updated_at": "2017-02-03T22:17:05.319Z", 
        "updated_by_id": 48481118
    }, 
    "cause": null, 
    "client": {
        "device_id": "92840a96-1d01-463c-956b-dff9594c2941", 
        "id": "498d3ffc44ddfa2f275b", 
        "instance_id": "f43da7f5-5be5-45b1-a70c-b3a9-7dc9583d", 
        "request_id": "15b8ced2-99b8-4798-8785-3827-91ff2fd9", 
        "user_id": "48481118"
    }, 
    "data": {
        "completed": true, 
        "completed_at": "2017-02-03T22:17:06.268Z", 
        "completed_by_id": 48481118, 
        "revision": 41, 
        "updated_at": "2017-02-03T22:17:06.271Z"
    }, 
    "enqueued_at": 1486160226.2807422, 
    "operation": "update", 
    "subject": {
        "id": 2501790935, 
        "parents": [
            {
                "id": 289113923, 
                "type": "list"
            }
        ], 
        "previous_revision": 40, 
        "revision": 41, 
        "type": "task"
    }, 
    "type": "mutation", 
    "user_id": 48481118, 
    "version": 1
}

URL Scheme

APIとは直接関係ない話になってしまいますが、
iPhoneにはURL Schemeという機構があり、URL形式のリンクをクリックすることでアプリを起動させることができます。(Androidでもあるんでしたっけ?)
WunderlistもURL Schemeに対応しているのですが公式ドキュメントにも説明がなかったので私が見つけたURL Schemeをメモしておきます。

アプリの起動

wunderlist://

特定のリスト

wunderlist://lists/:list_id

特定のタスク

wunderlist://tasks/:task_id

スター付きのタスク

wunderlist://lists/starred

期限が今日までのタスク

wunderlist://lists/today

期限が今週までのタスク

wunderlist://lists/week

すべてのタスク

wunderlist://lists/all

完了済みのタスク

wunderlist://lists/completed

自分に割り当てられたタスク

wunderlist://lists/assigned

感想

apiの構想がシンプルなので学習コストが低くすぐに使えるようになりました。
calbackの受取にすこしハマったのでそこくらいですね。