Scalatraの次期バックエンドをhttp4sにしようという計画は数年前からありつつ中々進んでいなかったのですが(ブランチに途中まで試みたと思われる残骸があるのですが、そもそもScalatraの開発自体が停滞しており絶賛放置されていました)、そろそろやってみようかと思いhttp4sを触り始めています。
http4sとは?
http4sはいわゆるノンブロッキングなHTTPツールキットで、今だとAkka HTTPが競合になるかと思います。http4sはAkka HTTP同様ルーティング用のDSLも備えていて単体でシンプルなWebフレームワークとして使用することもできます。
http4sの特徴の1つとして、http4s用に開発したアプリケーション(http4sではサービスと呼びます)を、サーブレットとして動かすためのアダプタが用意されているという点があります。現在ScalatraはサーブレットベースのWebフレームワークであることで、
- 既存のWebアプリケーションサーバに導入できる
- サーブレットベースの資産を活用できる
といったメリットがあります。これらは既存のJavaベースのシステムに部分的にScalaを導入して行く際に便利なのですが、バックエンドをhttp4sに移行することでサーブレットを使うか、ハイパフォーマンスなblaze(fs2)を使うかを選択することができるようになり、Scalatraの活用の幅がより広がるのではないかと思います。
http4sを動かしてみる
http4sのサービスはこんな感じで実装します(最新のマイルストーンビルドである0.18.0-M5を使用しています)。
package com.example.http4squickstart import cats.effect.IO import io.circe._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl object HelloWorldService extends Http4sDsl[IO] { val service = HttpService[IO] { case GET -> Root / "hello" / name => Ok(Json.obj("message" -> Json.fromString(s"Hello, ${name}"))) } }
blazeで動かす場合はこんな感じ。
package com.example.http4squickstart import cats.effect.IO import org.http4s.dsl.Http4sDsl import org.http4s.server.blaze.BlazeBuilder import org.http4s.util.StreamApp object BlazeServer extends StreamApp[IO] with Http4sDsl[IO] { def stream(args: List[String], requestShutdown: IO[Unit]) = BlazeBuilder[IO] .bindHttp(8080, "0.0.0.0") .mountService(HelloWorldService.service, "/") .serve }
サーブレットで動かす場合はこんな感じのリスナーを作っておけばOKです。これをxsbt-web-pluginで実行したり、warにしてサーブレットコンテナにデプロイする感じかと思います。
package com.example.http4squickstart import javax.servlet.annotation.WebListener import javax.servlet.{ServletContextEvent, ServletContextListener} import org.http4s.servlet.syntax.ServletContextSyntax @WebListener class Bootstrap extends ServletContextListener with ServletContextSyntax { override def contextInitialized(sce: ServletContextEvent) = { val context = sce.getServletContext context.mountService("helloService", HelloWorldService.service) } override def contextDestroyed(sce: ServletContextEvent) = () }
まだ細かいところまで見れていませんが、同じサービスがバックエンドを変えても動作することが確認できました。
http4sは国内ではだいぶマイナー感がありますが、Typelevelプロジェクトの1つ(まだIncubatorですが)ということもあり、海外ではそこそこ使われている気配があります。今のところ開発も活発ですが、Scalatraのバックエンドに採用したものの、肝心のhttp4sの開発が止まってしまうと厳しいので、そのあたりの様子も見つつ本当に移行できるかどうかを検討していきたいと思います。