Scala: Akka-HTTP を試してみる
Akka-HTTP とは、Spray++ という位置づけの新進気鋭の HTTPサーバ フレームワーク。
Reactive Stream を使って実装されているのが大きな特徴。
Spray は ベンチマーク で Finagle や wai (Haskell) に圧勝している。
Akka-HTTP もその流れを引き継ぎ、ハイパフォーマンスサーバに適したフレームワークになるだろうと期待している。
これまで Spray すら使ったことがなかったのだが、少しだけ Akka-HTTP に触れてみる。
Hello World with Akka-HTTP
/ping にアクセスすると "PONG" を返すシンプルな Webサーバを作る。
project/Build.scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import sbt. _ import sbt.Keys. _ object ApplicationBuild extends Build { lazy val buildSettings = Seq( organization := "com.github.mogproject" , version := "0.1.0-SNAPSHOT" , scalaVersion := "2.11.1" , scalacOptions ++ = Seq( "-deprecation" , "-unchecked" , "-feature" , "-encoding" , "utf-8" ), javacOptions ++ = Seq( "-source" , "1.7" ) ) lazy val resolverSettings = Seq( resolvers ++ = Seq( ), libraryDependencies ++ = Seq( "org.scalatest" %% "scalatest" % "2.2.0" % "test" , "com.typesafe" % "config" % "1.2.1" , "com.typesafe.akka" %% "akka-http-core-experimental" % "0.4" , "com.typesafe.akka" %% "akka-stream-experimental" % "0.4" ) ) lazy val testSettings = Seq( parallelExecution in Test := true ) lazy val root = Project( id = "akka-http-example" , base = file( "." ), settings = super .settings ++ buildSettings ++ resolverSettings ++ testSettings ) } |
src/main/resources/application.conf
akka { loglevel = INFO } |
src/main/scala/Boot.scala
- Scala Days 2014 資料のサンプルコード そのままでは型推論周りでコンパイルエラーとなった。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import akka.io.IO import akka.http.Http import akka.actor.ActorSystem import akka.pattern.ask import akka.util.Timeout import akka.http.model. _ import akka.http.model.HttpMethods. _ import scala.concurrent.duration. _ import akka.stream.scaladsl.Flow object Boot extends App { import system.dispatcher implicit val system = ActorSystem() implicit val askTimeout : Timeout = 500 .millis val bindingFuture = IO(Http) ? Http.Bind( "localhost" , 8080 ) bindingFuture foreach { binding = > Flow(binding.connectionStream) foreach { connection = > Flow(connection.requestProducer).map { case HttpRequest(GET, Uri.Path( "/ping" ), _ , _ , _ ) = > HttpResponse(entity = "PONG!" ) case _ = > HttpResponse( 404 , entity = "Unknown resource!" ) }.produceTo(connection.responseOut) } } } |
[error] akka-http-example/src/main/scala/Boot.scala:20: value connectionStream is not a member of Any [error] Flow(binding.connectionStream) foreach { connection ⇒ [error] ^ [error] one error found [error] (compile:compile) Compilation failed |
- 以下のように修正したら、動いた
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | import akka.io.IO import akka.http.Http import akka.actor.ActorSystem import akka.pattern.ask import akka.util.Timeout import akka.stream.{MaterializerSettings, FlowMaterializer} import akka.http.model. _ import akka.http.model.HttpMethods. _ import scala.concurrent.duration. _ import akka.stream.scaladsl.Flow object Boot extends App { import system.dispatcher implicit val system = ActorSystem() implicit val askTimeout : Timeout = 500 .millis val materializer = FlowMaterializer(MaterializerSettings()) val bindingFuture = IO(Http) ? Http.Bind( "localhost" , 8080 ) bindingFuture foreach { case Http.ServerBinding(localAddress, connectionStream) = > Flow(connectionStream).foreach { case Http.IncomingConnection(remoteAddress, requestProducer, responseConsumer) = > Flow(requestProducer).map { case HttpRequest(GET, Uri.Path( "/ping" ), _ , _ , _ ) = > HttpResponse(entity = "PONG!" ) case _ = > HttpResponse( 404 , entity = "Unknown resource!" ) }.produceTo(materializer, responseConsumer) }.consume(materializer) } } |
ルーティング
ロードマップによると、spray-routing に相当する DSLライブラリが akka-http (akka-http-core ではない) に組み込まれる予定とのこと。
現時点ではまだ無いのでパターンマッチで何とかするしかなさそう。
- 公式ドキュメントにかかれていたサンプル
1 2 3 4 5 6 7 8 9 10 11 12 | import HttpMethods. _ val requestHandler : HttpRequest ⇒ HttpResponse = { case HttpRequest(GET, Uri.Path( "/" ), _ , _ , _ ) ⇒ HttpResponse( entity = HttpEntity(MediaTypes.`text/html`, "<html><body>Hello world!</body></html>" )) case HttpRequest(GET, Uri.Path( "/ping" ), _ , _ , _ ) ⇒ HttpResponse(entity = "PONG!" ) case HttpRequest(GET, Uri.Path( "/crash" ), _ , _ , _ ) ⇒ sys.error( "BOOM!" ) case _: HttpRequest ⇒ HttpResponse( 404 , entity = "Unknown resource!" ) } |
0 件のコメント:
コメントを投稿