Akka HTTPでWeb APIに仕立てる
アクターとつないでみる
次に、Akka HTTPで受け付けたリクエストに対する処理を非同期に行うため、アクターにつないでみます。以前作ったレジ係アクター(CashierActor)やバリスタアクター(BaristarActor)にメッセージを送ってみましょう。
アクターへのメッセージ送信
/orderへのリクエストがあるとPUTされたJSON形式のオーダーを、最終的にコーヒーを作るバリスタアクターに定義されたOrder型にアンマーシャリングし、レジ係アクターに送ります。その後、レジ係アクターからの結果を待つことなく受け付けを完了した旨レスポンスします。
レジ係アクターを生成し、サーバー起動時にレジ係アクターに初期化(Initialize)メッセージを送り、カフェをスタートさせます。
// レジ係アクターを生成 val cashierActor = system.actorOf(CashierActor.props, "cashierActor") // HTTPサーバーの起動 val bindingFuture = Http().bindAndHandle(route, "localhost", 8080) bindingFuture .map { serverBinding => log.info(s"Server online at ${serverBinding.localAddress}") // 初期化メッセージを送信しカフェをスタートさせる cashierActor ! CashierActor.Initialize // ..
JSON形式をバリスタアクターに定義されたOrder型にマーシャリング・アンマーシャリングするマーシャラーを定義します。
import cafe._3_tellpattern.BaristaActor.Order // JSON形式とOrder型のマーシャリング・アンマーシャリング implicit val orderFormat = jsonFormat2(Order)
/orderへのPUTリクエストで送信されたJSON形式のオーダーを、Orderケースクラスにアンマーシャリングし、Orderメッセージをレジ係アクターに送信します。
val route: Route = path("order") { put { log.info("received PUT /order") entity(as[Order]) { order => // レジ係アクターへOrderメッセージを送信 cashierActor ! order complete(s"Received order: ${order.product} * ${order.count}") } } }
メッセージを送信すると、オーダーを受け付けたことを即座にレスポンスしました。
> http PUT http://localhost:8080/order product="Coffee" count:=10 HTTP/1.1 200 OK Content-Length: 27 Content-Type: text/plain; charset=UTF-8 Date: Mon, 10 Sep 2018 08:16:20 GMT Server: akka-http/10.1.5 Received order: Coffee * 10
リクエスト/レスポンス
アクターからの処理結果をレスポンスとしてクライアントに応答したい場合は、askパターン(「?」)でメッセージを送ります。askパターンでメッセージを送信するとFutureを返すため、レジ係アクターから応答があったときにその内容をレスポンスするようにします。
レジ係アクターにOrderを送信し、処理が正常に行われた場合はレジ係アクターからの完了メッセージをレスポンスとして返し、失敗した場合は例外メッセージをそのままレスポンスするようにします。
import cafe._4_askpattern.CashierActor.OrderCompleted val route = put { path("order") { entity(as[Order]) { order => log.info("receive PUT request /order") implicit val timeout: Timeout = 5.seconds // レジ係アクターへOrderを送信 val response: Future[Any] = cashierActor ? order // レジ係アクターからの応答を受信したときの処理 onComplete(response.mapTo[OrderCompleted]) { case Success(orderCompleted) => // 成功した場合は完了メッセージを返す complete(s"${orderCompleted.message}") case Failure(t) => // 失敗した場合は例外メッセージを返す complete(s"${t.getMessage}") } } } }
正常に処理された場合の実行結果は、次のようになります。
> http post http://localhost:8080/order product="Coffee" count:=10 HTTP/1.1 200 OK Content-Length: 11 Content-Type: text/plain; charset=UTF-8 Date: Mon, 10 Sep 2018 08:18:32 GMT Server: akka-http/10.1.5 ok
前回までに作成したAkkaのアクター同士がメッセージを送受信するアプリケーションが、Akka HTTPを使うことでWeb APIとして注文を受け付けることのできるシンプルなWebアプリケーションになりました。
さいごに
今回はAkkaの拡張機能のひとつであるAkka HTTPを使ってサーバーを起動し、Web APIを作成する方法を紹介しました。フルスタックなWebアプリケーションフレームワークを使用せずに、簡単にAPIを作成できることがお分かりいただけたことでしょう。なお、本記事で紹介したサンプルコードは、GitHub上で公開しています。
参考文献
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- 「PHP 7.3.0」リリース
- 「PHP 7.0.2/5.6.17/5.5.31」リリース
- 「PHP 7.0.3/5.6.18/5.5.32」リリース
- 「PHP 7.0.4/5.6.19/5.5.33」リリース
- 「PHP 7.1.6/7.0.20」リリース、「PHP 7.2 Alpha版」も
- 「PHP 7.1.6/7.0.20」リリース、「PHP 7.2 Alpha版」も
- 「PHP 7.0.9/5.6.24/5.5.38」リリース、PHP 5.5系列はサポート打ち切りへ
- 「PHP 7.1.5/7.0.19」リリース
- 「PHP 7.2.12/7.1.24」リリース
- 「PHP 7.2.11/7.1.23」リリース