DispatchでOAuth
Twitter APIのBASIC認証は2010年6月に「廃止予定」というのが気になっている。
今、Scalaの本を読んで勉強しているので、Scalaで何か書いてみたい。
Twitter APIについては、これまでJavaで Twitter4Jを使用してプログラムを書いていた。Scalaの場合でもTwitter4Jを使えば良いのだが、それだとScalaの勉強にはならないと思って、Scala用のOAuthライブラリを探してみた。
その結果、Dispatchというものしか見つけられなかったので、これを使ってstatus更新処理を書いてみると、以下のようになった。(出力されるAuthorize URLにアクセスして、そこから表示されるPINを入力する)
import dispatch._ import oauth._ import oauth.OAuth._ object TwitterTest { import Http._ val CONSUMER_KEY = "XXX...." val CONSUMER_SECRET = "XXX...." val CONSUMER = Consumer(CONSUMER_KEY, CONSUMER_SECRET) def main(args: Array[String]) { val http = fix(new Http) val req_token = http(Auth.request_token(CONSUMER)) println(req_token) val authorize_url = Auth.authorize_url(req_token) println("Authorize URL: " + authorize_url.to_uri) print("PIN: ") var PIN = readLine val (access_token: Token, user_id: String, screen_name: String) = http(Auth.access_token(CONSUMER, req_token, PIN)) println(access_token) println("ACCESS_TOKEN value: " + access_token.value) println("ACCESS_TOKEN secret: " + access_token.secret) println("user_id: " + user_id) println("screen_name: " + screen_name) val status = "更新テスト#1です。" val res = http(Status.update(status, CONSUMER, access_token)) println(res) } def fix(http: Http): Http = { // WARNING // Invalid cookie header: "Set-Cookie: ..... // .... Unable to parse expires attribute: .... import org.apache.http.cookie.params.CookieSpecPNames http.client.getParams(). setParameter(CookieSpecPNames.DATE_PATTERNS, java.util.Arrays.asList("EEE, dd MMM-yyyy-HH:mm:ss z", "EEE, dd MMM yyyy HH:mm:ss z")) http } } import json._ import JsHttp._ object Twitter { val host = :/("twitter.com") } object Auth { val svc = Twitter.host / "oauth" def request_token(consumer: Consumer): Handler[Token] = request_token(consumer, OAuth.oob) def request_token(consumer: Consumer, callback_url: String) = svc.secure / "request_token" << OAuth.callback(callback_url) <@ consumer as_token def authorize_url(token: Token) = svc / "authorize" <<? token def authenticate_url(token: Token) = svc / "authenticate" <<? token def access_token(consumer: Consumer, token: Token, verifier: String) = svc.secure.POST / "access_token" <@ (consumer, token, verifier) >% { m => (Token(m).get, m("user_id"), m("screen_name")) } } object Status extends Request(Twitter.host / "statuses") { def update(status: String, consumer: Consumer, token: Token) = new UpdateStatusBuilder(status, consumer, token) class UpdateStatusBuilder(status: String, consumer: Consumer, token: Token) extends Builder[Handler[JsObject]] { def product = Status / "update.json" << Map("status" -> status) <@ (consumer, token) ># obj } }
fix()の処理は省いても動作するが、警告が表示されるので追加しておいた。
Dispatchの使い方自体がよくわからないので苦労したが、型情報を頼りに試行錯誤した結果、とにかく動いた。