Sprayの簡単な紹介
Scala Advent Calendar 2013の10日目担当記事です。みんなガチな人ばかりで怖いです。あまり期待しないでください。
ググっても日本の記事があまりないSprayの紹介をしてみます。
あと表題と関係ないですが最近書いたPlayFrameworkにSlickやSecureSocialを入れたメモを掲載しておきます。
Sprayについて
Akkaをベースに非同期モデルで実装された超ハイパフォーマンスなHTTP処理フレームワークという感じのもの。型システムがあって非同期でマルチスレッド(アクター)対応しててプラグインがある程度揃ってるHTTPサーバやWebフレームワークってScalaにしばらなくても少なそうです。ハイフリークエンシ―なWebアプリケーションやREST-APIを作るフレームワークとしての用途を想定していると思います。
SprayはJettyを使ってサーブレットとして動かすことも出来るし、スタンドアロンなWebサーバとして動かすことも出来ます。スタンドアロンのはspray-canというやつです。プラグイン等々githubリポジトリで配布されてます。
ざっくりと機能を挙げると
- akkaベースでパイプラインアーキテクチャのHTTP処理
- サーブレットとしてもスタンドアロンでも実行可能
- もちろんsbtとの親和性高い (ホットリロード機能など可)
- ルーティングをきめ細かく制御できる
- JSONとScalaオブジェクトのマッピング, 自動マーシャル・アンマーシャル
- Slick(DAO)に対応
- アセットコンパイル的なことをやってくれるsbtプラグイン
- Twirl(テンプレートエンジン)対応
- ベーシック認証はビルトインで対応
- SSL対応
高効率なサーバサイドに特化したWebアプリケーションフレームワークという感じです。
なんといってもベンチマークが凄いです。JVM系最速でサーブレットコンテナよりも速い。そこのベンチを見ると爆速という噂のHaskellのWAIはJVM系と比べると少しオーバーヘッドがあるのですね。Haskell+WAIは非同期処理のモナディックなノーテーションが欲しいときに使うんだ!という人に朗報なのが、SprayはScala上に上手くDSLを組み立てていて単純なモナドよりももっと小回り効く処理記述が出来そうです。
サンプルを動かす
必要なものはScalaとsbtがあればOKで、spray-canをgit cloneしてsbt updateすればakkaだの必須プラグインだのは全部そろえてくれます。
# git clone git://github.com/spray/spray-template.git my-project # cd my-project # sbt # re-start
デフォルトだとlocalhostにバインドするのでsrc/main/scala/com/example/Boot.scalaを編集して0.0.0.0にバインドして8080にアクセスします。
package com.example import akka.actor.{ActorSystem, Props} import akka.io.IO import spray.can.Http object Boot extends App { implicit val system = ActorSystem("on-spray-can") val service = system.actorOf(Props[MyServiceActor], "demo-service") IO(Http) ! Http.Bind(service, interface = "0.0.0.0", port = 8080) }
これを見ると分かるようにサービス用のアクターを作って、それをバインドオブジェクトで包んでIOレイヤのアクターに渡すという構造ですね。綺麗なスタックです。
サービスのアクターの本体も見てみます。src/main/scala/com/example/MyService.scalaです。
package com.example import akka.actor.Actor import spray.routing._ import spray.http._ import MediaTypes._ class MyServiceActor extends Actor with MyService { def actorRefFactory = context def receive = runRoute(myRoute) } trait MyService extends HttpService { val myRoute = path("") { get { respondWithMediaType(`text/html`) { complete { <html> <body> <h1>Say hello to <i>spray-routing</i> on <i>spray-can</i>!</h1> </body> </html> } } } } }
HttpServiceを継承したクラス内でルーティング用のDSLを使って色々書く感じですね。HTTPパイプライニング的な処理をメソッドチェーンではなく関数のネストのように書けるのがいい感じです。上述したベンチマークにも掲載されてるJavaの爆即RESTフレームワークrestexpressはメソッドチェーン的に書く必要があるので、他のREST用フレームワークと比べてこのSprayは記述の柔軟性が特に高いと思います。
という感じで、Jsonとcaseオブジェクトのマッパ―を入れて自動マーシャル化を試すつもりでしたがタイムアップなのでここまでですみません。Sprayは本気で使うかもしれないのでそうなったらまた記事書きます。