概要
WeekendEngineerというグループの中で9月にPlayFrameworkを使ったTwitterツールの開発をしました。レスポンスが遅くて辛い。。。
GitHub/ochiai_auto_tweet
その際にPythonを使ったWebAPIと連携をするためにWSClientを使いました。備忘録のためにもPlayFramework2.6のWSClientを使って外部のWeb APIとやりとりをする方法を残しておきます。
やりたいこと
- 以下の仕様のAPIを叩く。
url | response |
---|---|
generate_tweet/:twitter_id | {"tweet": "texttext..."} |
- 生成されたテキストを取得する
実装方法
コード
client.TweetGeneratorClient.scala
@Singleton
class TweetGeneratorClient @Inject()(ws: WSClient) extends ITweetGeneratorClient {
def generateTweet(twitterId: String): Tweet = {
val request: WSRequest = ws.url("http://127.0.0.1:5000/generate_tweet/" + twitterId)
val futureResult: Future[String] = request.get().map{
response => (response.json \ "tweet").as[String]
}
val tweetText: String = Await.result(futureResult, Duration.Inf)
return Tweet.createNewTweet(tweetText)
}
}
解説
wsclientにAPIのURLを設定
WSClientクラスのインスタンスをDIします。
client.TweetGeneratorClient.scala
@Singleton
class TweetGeneratorClient @Inject()(ws: WSClient) extends ITweetGeneratorClient {
}
ws#url(url: String)
の引数にAPIのURLを指定します。
client.TweetGeneratorClient.scala
def generateTweet(twitterId: String): Tweet = {
val request: WSRequest = ws.url("http://127.0.0.1:5000/generate_tweet/" + twitterId)
}
レスポンス(JSON)から文字列を抽出
request#get()
メソッドで取得したresponseのjsonから、"tweet"というキーの値を取得します。
(response.json \ "key名").as[String]
で、指定したキーを文字列で抜き出せるみたいです。
client.TweetGeneratorClient.scala
def generateTweet(twitterId: String): Tweet = {
val request: WSRequest = ws.url("http://127.0.0.1:5000/generate_tweet/" + twitterId)
val futureResult: Future[String] = request.get().map{
response => (response.json \ "tweet").as[String]
}
val tweetText: String = Await.result(futureResult, Duration.Inf)
return Tweet.createNewTweet(tweetText)
}
ちなみに
以下のコードは{person: {name: ""}}
のようなネストしたJSONから文字列を取得する例です。
(公式ドキュメントより拝借)
val futureResult: Future[String] = ws.url(url).get().map {
response =>
(response.json \ "person" \ "name").as[String]
}
他にもJavaでおなじみJacksonのscala-moduleも使えます。
最後に
これでPluginの出ていないような外部APIを叩いて、レスポンスを受け取ることができますね。Webサービスから提供されるAPIのレスポンスは複雑なJSON配列であることが珍しくないので、jackson-module-scalaにも挑戦してみようかなと思います。