Scala用の超シンプルなREST APIフレームワークとしてRestyというものを作っています。
takezoe.hatenablog.com
github.com
前回ブログで書いてからちょこちょこいじりつつバージョンアップを重ねているので、前回のブログで紹介できなかった機能や、これまでに新たに追加した機能について簡単にまとめてみたいと思います。
全自動Zipkin
Restyはもともと全自動でSwagger、Hystrixと連携する機能を備えていましたが、これに加えてZipkinも全自動で利用できるようになりました。
以下のようにコントローラーにHttpClientSupport
というトレイトをミックスインし、このトレイトが提供するメソッドを使用して別サービスの呼び出しを行うことでZipkinでトレースを行うことができます。
class HelloController extends HttpClientSupport {
@Action(method = "GET", path = "/hello/{id}")
def hello(id: Int): Message = {
val user = httpGet[User](s"http://localhost:8080/user/${id}")
Message(s"Hello ${user.name}!")
}
}
なお、全自動と言いつつweb.xmlで少しだけ設定が必要です。Zipkinインテグレーションを使用するかどうか、サンプリングレート、ZipkinサーバのURLを指定します。
<context-param>
<param-name>resty.zipkin</param-name>
<param-value>enable</param-value>
</context-param>
<context-param>
<param-name>resty.zipkin.sample.rate</param-name>
<param-value>1.0</param-value>
</context-param>
<context-param>
<param-name>resty.zipkin.server.url</param-name>
<param-value>http://127.0.0.1:9411/api/v1/spans</param-value>
</context-param>
web.xmlでの設定
全自動SwaggerやHystrixが使えるのは便利なのですが、セキュリティ上運用時はエンドポイントを無効にしたいというケースもあるはずなのでweb.xmlで設定できるようにしました。
どちらもデフォルトでは無効になっており、web.xmlに以下の設定を追加することで有効になります。
<context-param>
<param-name>resty.swagger</param-name>
<param-value>enable</param-value>
</context-param>
<context-param>
<param-name>resty.hystrix</param-name>
<param-value>enable</param-value>
</context-param>
今後はもう少し設定可能なパラメータを増やしていこうと思っています。
ケースクラスのバリデーション
JSONをマッピングするケースクラスのコンストラクタでassert
することで入力値のバリデーションができるようになりました。
case class Message(message: String){
assert(message.length < 10, "message must be less than 10 charactors.")
}
以下のようなレスポンスが400 BadRequest
ステータスで返却されます。
{
"errors": [
"message must be less than 10 charactors."
]
}
もう少し本格的なバリデーションフレームワークを入れようかなとも思ったのですが、Restyはシンプル第一なので標準機能としてはこのくらいにしておこうと思います。
ServletAPIへのアクセス
Restyのコントローラーは基本的にServlet API非依存ですが、Restyが提供する機能だけでは不可能な細かい処理を行う必要がある場合や、HttpSession
を使用したい場合など、Servlet APIを使う必要がある場合はコントローラーにServletAPI
トレイトをミックスインするとrequest
、response
でHttpServletRequest
、HttpServletResponse
にアクセスできるようになります。
class HelloController extends ServletAPI {
@Action(method = "GET", path = "/hello")
def hello(): Message = {
val name = request.getParameter("name")
Message(s"Hello ${name}!")
}
}
まとめ
Restyは関数型プログラミングや非同期処理の知識がなくてもScalaで簡単にJSONベースのREST APIを実装することができます。サンプルプロジェクトから始めるのが手っ取り早いと思いますので興味のある方は是非試してみていただければと思います。
github.com