Play2 WS 再入門
2014 / 5 / 24 (Sat)
注意:LT(ライトニングトーク)のため、
光速談話ご容赦ください
アジェンダ
自己紹介
経歴
普段は、Salesforceの導入をやっています。
(SalesforceといえばHeroku、HerokuといえばPlayframework)
タイトルのWSについて
今日の目標と結果
今日の目標と結果
Play2.2-WS 再入門
WS 再入門に必要な基礎知識
今回は5つ
1. Action
2. scala.concurrent.Future
3. play.api.libs.json.Reads
(つづく)
WS 再入門に必要な基礎知識(つづき)
4. Implicit Parameter
5. Option
(外部サービスのAPIキーの取得方法は省略します)
1. Action
1. 認証画面へのリダイレクト
2. 受け取ったレスポンスから再リクエスト
conf/routes
GET /login controllers.Application.login
GET /auth/salesforce/callback controllers.Application.apiCall(code :String)
1. Action(認証画面へリダイレクト)
val loginUrl = "https://login.salesforce.com/services/oauth2/authorize"
val redirectUrl = "http://localhost:9000/auth/salesforce/callback"
val clientId = "REPLACE_TO_YOUR_CLIENT_ID"
def login = Action {
val url = loginUrl + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + redirectUrl
Redirect(url)
}
1. Action(レスポンスから再リクエスト)
val tokenUrl = "https://login.salesforce.com/services/oauth2/token"
val clientSecret = "REPLACE_TO_YOUR_CLIENT_SECRET"
def apiCall(code :String) = Action.async {
val url = tokenUrl + "?code=" + code + "&grant_type=authorization_code&client_id=" + clientId + "&client_secret=" + clientSecret + "&redirect_uri=" + redirectUrl
WS.url(url).get().flatMap { response =>
val sfdc :SFDCToken = (response.json).as[SFDCToken]
val reqUrl = sfdc.instance_url + "/services/data/v29.0/query/"
val atoken = "OAuth " + sfdc.access_token
val query = "SELECT Id, Subject, Description FROM Case"
WS.url(reqUrl).withHeaders("Authorization" -> atoken).withQueryString("q" -> query).get().map {
response2 => Ok(response2.body)
}}}
1. Action(ポイント)
Future[Response]型で受け取る場合
val futureResponse :Future[Response] = WS.url(url).get()
2. scala.concurrent.Future
2. scala.concurrent.Future
WS.url(url).get().flatMap { response =>
val sfdc :SFDCToken = (response.json).as[SFDCToken]
val reqUrl = sfdc.instance_url + "/services/data/v29.0/query/"
val atoken = "OAuth " + sfdc.access_token
val query = "SELECT Id, Subject, Description FROM Case"
WS.url(reqUrl).withHeaders("Authorization" -> atoken)
.withQueryString("q" -> query).get().map {
response2 => Ok(response2.body)
}
}
IN
OUT
OUT
IN
2. scala.concurrent.Future(注意点)
Listの例
scala> List(1,2,3) map { x => List(1,2) map( x * _) }
res1: List[List[Int]] = List(List(1, 2), List(2, 4), List(3, 6))
scala> List(1,2,3) flatMap { x => List(1,2) map( x * _) }
res3: List[Int] = List(1, 2, 2, 4, 3, 6)
3. play.api.libs.json.Reads
3. play.api.libs.json.Reads
case class SFDCToken(id: String, issued_at: String, refresh_token: Option[String], instance_url: String, signature: String, access_token: String)
implicit val sfdcTokenReads: Reads[SFDCToken] = Json.reads[SFDCToken]
WS.url(url).get().flatMap { response =>
val sfdc :SFDCToken = (response.json).as[SFDCToken]
val reqUrl = sfdc.instance_url + "/services/data/v29.0/query/"
val atoken = "OAuth " + sfdc.access_token
val query = "SELECT Id, Subject, Description FROM Case"
(中略)
}}
JSON
case class
Reads
3. play.api.libs.json.Reads(ポイント)
case class SFDCToken(id: String, issued_at: String, refresh_token: Option[String],
instance_url: String, signature: String, access_token: String)
implicit val sfdcTokenReads: Reads[SFDCToken] = Json.reads[SFDCToken]
implicit val sfdcTokenReads: Reads[SFDCToken] = (
(__ \ "id").read[String]
and (__ \ "issued_at").read[String]
and (__ \ "refresh_token").read[String]
and (__ \ "instance_url").read[String]
and (__ \ "signature").read[String]
and (__ \ "access_token").read[String]
)(SFDCToken)
JSONの構造をマップ
4. Implicit Parameter
WS.url(url).get().flatMap { response =>
val sfdc :SFDCToken = (response.json).as[SFDCToken]
(中略)
}
注目
JSON
case class
4. Implicit Parameter
!?
4. Implicit Parameter
「as」 だけで
マーシャリング!?
4. Implicit Parameter
いいえ、「暗黙パラメータ」です。
implicit val sfdcTokenReads: Reads[SFDCToken] = Json.reads[SFDCToken]
WS.url(url).get().flatMap { response =>
val sfdc :SFDCToken = (response.json).as[SFDCToken] (sfdcTokenReads)
(中略)
}
5. Option
(トラブルシューティング)
レスポンスのJsonに項目が含まれないときがある場合
定義:6つ
case class SFDCToken(id: String, issued_at: String, refresh_token: String,
instance_url: String, signature: String, access_token: String)
実際のJSON:5つ
{ “id”:”https://login.salesforce.com/id/00D10000000ZlJIEA0/005100000029TlhAAE”, “issued_at”:”1400685904843”, “instance_url”:”https://ap.salesforce.com”, “signature":"eIh1n+JjbFIMfEZQoE6hgW2lwuEWmn7iklS1Ue7FitE=",
"access_token":"00D10000000ZlJI!AR4AQLuB8z3DBjRCq25YyOObiPAE"}
①
②
③
④
⑤
⑥
①
②
⑤
⑥
④
5. Option
5. Option
その場合は、Optionをつけてあげましょう
case class SFDCToken(id: String, issued_at: String, refresh_token: Option[String],
instance_url: String, signature: String, access_token: String)
val rtoken :String = sfdc.refresh_token.getOrElse(“”)
まとめ
ご清聴ありがとうございました。
参考(1)
参考(2)