twitterを支えるfinatraを使ってみた

ChainZ(クリエイター)
いろいろやってます。

finatra

finatra(https://twitter.github.io/finatra/)はSinatraからアイデアを得て、twitterSeverを使って作られたScalaベースのwebフレームワークです。この記事を書いた時点で、最新のバージョンは2.0です。

Hello World

finatraのリポジトリ(https://github.com/twitter/finatra)にあるexamples/finatra-hello-worldを使います。 README.mdには既に詳しいディプロイ方法が載ってありますが、起動方法は下記のコマンドを叩く:

./sbt -Dlogback.configurationFile=src/test/resources/logback-test.xml run

portを変える
このプロジェクトはデフォルトに8888(フロント)と9990(内部用)を使っていますが、もしいずれかのportは既に他のアプリに使われたりしたら、エラーがでます。portを変えるには、runの後ろに、-http.port=:1212(フロント)、-admin.port=:9911(内部用)というオプションを追加してください。

ブラウザを開いて、http://localhost:8888/hi?name=Worldにアクセスすると

ServerとControllerをつくてみる

先ほどのHello Worldプロジェクトでは、既にHelloWorldSeverHelloWorldControllerが 用意されたので、特に何もしなくてもサイトとして動きます。これから、自分でServerとControllerを作ってみます:

Server

./src/main/scala/jp/co/befool/biiBiiServer.scalaを作成します。

この記事のコードがパッケージjp.co.befool.biiにあります。パッケージというコンセプトが分かる方は、自分好きなパッケージにしても大丈夫です。

package jp.co.befool.bii
import com.twitter.finatra.http.HttpServer
import com.twitter.finatra.http.routing.HttpRouter
import com.twitter.finatra.http.filters.CommonFilters
// finatraのHttpServerを拡張
class BiiServer extends HttpServer {
// routerなど設定
override def configureHttp(router: HttpRouter) {
router
.filter[CommonFilters] // Commonフィルターが必要です
}
}
// BiiServerのエントリーポイント
object BiiServerMain extends BiiServer

Controller

./src/main/scala/jp/co/befool/bii/controller/RootController.scalaを作成します:

package jp.co.befool.bii.controller
import com.twitter.finatra.http.Controller
import com.twitter.finagle.http.Request
// finatraのControllerを拡張
class RootController extends Controller{
// http://localhost
get("/") { request: Request =>
response.ok.body(s"<h1>HelloWorld</h1>")
}
}

BiiServerからRootControllerにルートします:

import jp.co.befool.bii.controller.RootController
// finatraのHttpServerを拡張
class BiiServer extends HttpServer {
// routerなど設定
override def configureHttp(router: HttpRouter) {
router
.filter[CommonFilters] // Commonフィルターが必要です
.add[RootController] // RootControllerを追加
}
}

コマンドsbt runすると

[warn] Multiple main classes detected. Run 'show discoveredMainClasses' to see the list
Multiple main classes detected, select one to run:
[1] com.twitter.hello.HelloWorldServerMain
[2] jp.co.befool.bii.BiiServerMain
Enter number:

サーバーが二つ検出されたので、どっちを実行するかという質問です。2で入力します。問題なければ、ブラウザでhttp://localhost:8888で見ると:

サーバーちゃんと動いています。

RequestのValidationをやってみます

先ほど作ったRootControllerの直前に、RootRequestを作成します:

import com.twitter.finatra.request.QueryParam
import com.twitter.finatra.validation.NotEmpty
case class RootRequest (
// @NotEmpty記号は空値が不可ということです
// @QueryParamは@NotEmptyの対象パラメータ名です
@NotEmpty @QueryParam name: String
)

RootControllerget("/")ルートに修正を入れます:

get("/") { request: RootRequest =>
response.ok
.header("Content-Type", "text/html; charset=utf-8")
.body(s"<h1>こんにちは、${request.name}</h1>")
}

requestのタイプを先ほど作ったRootRequestに宣言します。

sbt runして、ブラウザでhttp://localhost:8888にアクセスして、下記のエラーが表示されます:

URLをhttp://localhost:8888/?name=世界にして、アクセスすると:

Requestのバリデーション動いてるとわかりますね。

まとめ

finatraに興味ある方は、より詳しい説明と使い方が公式のリポジトリに載っています:https://github.com/twitter/finatra/blob/master/http/README.md

オープンソースのwebフレームワークとしては、finatraのドキュメントなどはまだ不足してる感じがします。しかし、twitterという超大手なweb企業が使ってるというとこが、魅力を感じる人もいるでしょう(自分はそうでした)。次回はfinatraを利用してアプリのバックエンドを作ってみようと思います。