SwiftでWunderlistのAPI使ってみた
Todoistに続き、WunderlistからもAPIを使ってデータを取ってみました。 これからはGitHubにサンプルも上げていこうと思うので、もしコードをみたい方がいればそちらも見てみてください。
全体的な流れはTodoistの時と基本は全く同じなのですが、Wunderlistの方がドキュメントはしっかりしており、パラメータも単にURLにつけるだけではなくHTTPのbodyやheaderにつけないといけなかったりしました。 しかし、パラメータのつけ方だけ気をつければ基本的には大丈夫だと思います!
参考サイト
事前準備
毎回のことですが、こちらからClient_IDとClient_Secretを取得します。
認証
認証もOAuthなので基本的にやることは同じです。
STEP1
リクエストを送信します。エンドポイントは以下のとおりです。
https://www.wunderlist.com/oauth/authorize?client_id=ID&redirect_uri=URL&state=RANDOM
パラメータは3つ
- client_id : クライアントID
- redirect_uri : リダイレクトURL
- state : ランダムな文字列
Todoistのときはredirect_uriがoptionalでwebで設定できたのですが、Wunderlistではrequiredになっていました。
こちらは前回同様WebViewを利用してリクエストを送信しています。 以下のように認証用にWebViewを持つだけのシンプルなVCを作って実装しました。
class Wunderlist { private struct Info { static let client_id = "your_client_id" static let client_secret = "your_client_secret" static let redirect_uri = "https://localhost/" static let state = "state" static var code: String? = nil static var access_token: String? = nil { didSet { let ud = NSUserDefaults.standardUserDefaults() ud.setValue(access_token, forKey: Wunderlist.accessTokenPath) } } } private let authRequestURL = "https://www.wunderlist.com/oauth/authorize?client_id=\(Info.client_id)&redirect_uri=\(Info.redirect_uri)&state=\(Info.state)" // --<略>-- } class WunderlistAuthController: UIViewController, UIWebViewDelegate { override func viewDidLoad() { super.viewDidLoad() webView = UIWebView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height)) webView!.delegate = self view.addSubview(webView!) if let url = NSURL(string: Wunderlist.sharedInstance.authRequestURL) { webView!.loadRequest(NSURLRequest(URL: url)) } } }
STEP2
ユーザーが認証・許可をするとリダイレクトしてくれるので、WebViewでそれを拾って、access_tokenを取得するためのリクエストを送信します。
まず、URLからcodeを取得します。 shouldStartLoadWithRequestの中でリダイレクト先と一致していた場合、codeを取得するようにしました。
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { if let url = request.URL { if url.host == Wunderlist.sharedInstance.redirectHost { let query = url.query! // query forms "state=state&code=<code>" let code = query.substringFromIndex(advance(query.startIndex, 17)) println("query: \(query),code: \(code)") Wunderlist.sharedInstance.getAccessToken(code) return true } } return true }
次にリクエストをPOSTします。
パラメータは3つ
- client_id: クライアントID
- client_secret: クライアントsecret
- code: 先ほど取得したcode
このパラメータなのですが、Todoistの時とは違い、HTTPBodyに記述します。 なのでコードは以下のような感じになります。
private let accessTokenRequestURL = "https://www.wunderlist.com/oauth/access_token" private var accessTokenHTTPBody: String? { get { if let code = Info.code { return "client_id=\(Info.client_id)&client_secret=\(Info.client_secret)&code=\(code)" } return nil } } private func getAccessToken(code: String) { Info.code = code let request = NSMutableURLRequest(URL: NSURL(string: accessTokenRequestURL)!) request.HTTPMethod = "POST" var bodyData = accessTokenHTTPBody! request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding); NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (_, data, _) in let dataString = NSString(data: data, encoding: NSUTF8StringEncoding) let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary Info.access_token = jsonResult["access_token"] as? String self.delegate?.didAuthrization(true) }) }
これでリクエストを送信すると、無事access_tokenが取得できます。
データの取得
データ取得に関しての注意点
データを取得するためのリクエストにはaccess_tokenを添付する必要がありますが、wunderlistはHTTPのヘッダーの中に情報を格納するように要求しています。 また、X-Access-TokenとX-Client-IDというフィールドを作成する必要があります。 なので、リクエストを作成する際に、以下のようにしてヘッダーを追加します。
今回はエンドポイントを受け取りNSMutableURLRequestにして返す関数を作成しました。 その中でヘッダーにclient_idとaccess_tokenの情報を追加しています。
private func getRequest(endpoint: String) -> NSMutableURLRequest? { if let url = NSURL(string: endpoint) { let request = NSMutableURLRequest(URL: url) request.addValue(Info.access_token, forHTTPHeaderField: "X-Access-Token") request.addValue(Info.client_id, forHTTPHeaderField: "X-Client-ID") return request } return nil }
Listの取得
taskを取得するためには、まずlistを取得してlist_idを知る必要があります。
listを取得するためのエンドポイントはhttps://a.wunderlist.com/api/v1/lists
です。
パラメータは特に必要ないので、とりあえずリクエストをおくります。
WunderlistのAPIに関するクラスにgetメソッドを作り、引数としてenumで宣言しておいた何が欲しいかの情報を渡します。 返ってきたjsonからidやtitleなどの情報を取得します。
サンプルの中では、listを取得した際にidを利用してtaskを取得するようにしています。
Wunderlist.sharedInstance.get(.List) { if let array = $0 { for listObj in array { let list = listObj as! NSDictionary let id = list["id"] as! NSNumber let title = list["title"] as! String println("list: id=\(id), title=\(title)") self.getTasks(id.stringValue) self.lists.append(list) } } }
Taskの取得
listを取得した後には、list_idを利用してtaskを取得します。
エンドポイントはhttps://a.wunderlist.com/api/v1/tasks
で、必要なパラメータはlist_idです。
また、パラメータにcompletedを追加すると完了済み/未完了のタスクを指定して取得することもできます。
func getTasks(listID: String) { Wunderlist.sharedInstance.get(.Task, parameters: ["list_id":listID]) { if let array = $0 { for taskObj in array { let task = taskObj as! NSDictionary let id = task["id"] as! NSNumber let title = task["title"] as! String let completed = task["completed"] as! NSNumber let due = task["due_date"] as? String println(" task: id=\(id), title=\(title), due=\(due), completed=\(completed.boolValue)") self.tasks.append(task) } } } }