こんにちは、Xiaoです。
最近Akka HTTPの正式版 X がで出ましたね。 自分は前からAkka HTTPに興味があって、ちょうどいい機会なので、Akka HTTPを詳しく勉強するため、簡単のWebサービスを作ってみたいと思います。
LINE Bot とは
LINE が提供する Messaging API により、LINEのトーク画面を使った対話型Botアプリケーションの開発が可能になります。
※ Image taken from developers.line.me
この図を説明すると、
- サーバのURLを LINE Bot にするアカウントと繋ぎます。
- ユーザがBotに対して、友たち追加、メッセージ送信などを行う際に、設定されたサーバにイベント情報が送られます。
- サーバがイベント情報を基づいて、LINE Messaging API経由でユーザに返信できます。
※ LINE アカウントの設定について、LINEの公式ドキュメントに記載されているので、割愛します。
Akka HTTPについて
Akka HTTP は Akka Actor と Akka Stream をベースに作られた、HTTPサーバ/クライエント処理をサポートするためのツール、ライブラリです(フレームワークではありません!)。
LINE botを作るには、Akka HTTP みたいなツールが丁度良いと思います。
今回で作る Bot
今回は Akka HTTP の特性の紹介するため、一番シンプルな「受けたメッセージをそのまま返す」Botを例にして、Akka HTTP の特性を幾つか紹介したいと思います。
- JSON を変換する ((un)Marshalling)
- HTTP request を処理する
- HTTP request を送る
最終のコードは こちら でたどり着けます。
TL;DR
JSON を変換する ((un)Marshalling)
LINE Messaging API とのやりとりは全部JSONを扱っています。これに対して、Akka HTTP の特徴の一つは、(un)Marshalling 機構によって、JSON、 XML或いはバイナリデータを簡単サポート出来ます。
◆ spray-jsonモジュールを使ため、Dependencyに"akka-http-spray-json"を追加。
"com.typesafe.akka" %% "akka-http-spray-json" % "10.0.0"
◆ 次は、スコープ内に RootJsonFormat[T] を用意する。
- Case Class がある場合、要素の数に応じて、jsonFormatX メソッドを使えばいいです。
- それ以外の場合、RootJsonFormat[T] を実装する必要があります。
※ 詳しい説明は spray-json を参照ください。
◆ 最後、Marshalling と Unmarshalling 機構を使うため、SprayJsonSupport を導入する。
Reply Message API のRequestをJSONに変換したい場合は、こんな感じです。
case class TextMessage(`type`: String = "text", text: String) case class Messages(replyToken: String, messages: List[TextMessage]) trait MessagesJsonSupport extends SprayJsonSupport with DefaultJsonProtocol { implicit val textMessageFormat = jsonFormat2(TextMessage) implicit val messageFormat = jsonFormat2(Messages) }
HTTP requestを処理する
ユーザがBotに対して、友たち追加、メッセージ送信などを行う際に、設定されたサーバにイベント情報が送られます。 HTTP サービスをシンプルに実装出来るため、Akka HTTP は High Level Routing DSL を提供しています。
こんな感じで使います。
def routes: Route = { path("line" / "callback") { (post & entity(as[Events])) { request => ... complete { "OK" } } } }
見た目の通り、今回は以下のDSLを使いました。
- path("line" / "callback") はサービスのエンドポイントURLです。
- (post & entity(as[Events])) は POST メソッドをマッチし、Requestデータを Events に変換します。
- complete は処理成功を表します。
※ 詳しい説明は High-level Server-Side API を参照ください。
関連するコードは こちら で参照できます。
HTTP request を送る
ユーザに返信する場合、LINE の Reply Message API を経由で実現します。
Akka HTTPでは、こんな感じで書けます。
val auth = headers.Authorization(OAuth2BearerToken(accessToken)) val content = Messages( replyToken = token, messages = List(TextMessage(text = message)) ) val request = RequestBuilding.Post( uri = "https://api.line.me/v2/bot/message/reply", content = content ).withHeaders(auth) val responseFuture: Future[HttpResponse] = Http().singleRequest(request)
- Akka HTTPは、Authorization 機構を通じで、OAuth認証などをサポートしています。
- RequestBuilding を使って、Requestを作成していますが、HttpRequest を直接実装するのもできる。
- HTTPコネクションを管理したくない場合、一番簡単な Http().singleRequest を使います。
※ 詳しい説明は Consuming HTTP-based Services (Client-Side) を参照ください。
関連するコードは こちら で参照できます。
まとめ
今回はテキストベースのBotに必要のものを紹介しました。
後は、DBやAkka Presistenceを使えば、情報を保持出来るBotを作れるし、他の 3rd Party API に繋げば、いろんなサービスを提供することが出来ます。