軽量finchを試してみました。2018年2月リリースのfinchを落としてきて、参考リンクのコーディングを基に動かそうとしたが、コンパイルが通らなかったので手を加えてみました。
build.sbt
libraryDependencies ++= Seq(
"com.twitter" %% "finagle-mysql" % "18.3.0",
"com.github.finagle" %% "finch-core" % "0.17.0",
"com.github.finagle" %% "finch-argonaut" % "0.17.0",
"com.twitter" %% "finagle-http" % "18.3.0",
"com.github.finagle" %% "finch-circe" % "0.17.0",
"io.circe" %% "circe-core" % "0.9.1",
"io.circe" %% "circe-generic" % "0.9.1",
"ch.qos.logback" % "logback-classic" % "1.1.3"
)
Main.scala
package jp.co.finchitest
import com.twitter.finagle.http.{Request, Response}
import com.twitter.finagle.{Http, Service}
import com.twitter.util.Await
import io.circe.generic.auto._ // *
import io.finch._
import io.finch.circe._ // *
import io.finch.syntax._
import jp.co.finchitest.helpers.MysqlHelper._
import jp.co.finchitest.forms._
import jp.co.finchitest.forms.UserForm._
object Main {
val listUser: Endpoint[Seq[User]] = get("users") {
User.all.map{
case Seq() => NotFound(new Exception("Record Not Found"))
case users => Ok(users)
}
}
val showUser: Endpoint[User] = get("users" :: path[Long]) {id: Long =>
User.find(id).map {
case None => NotFound(new Exception("Record Not Found"))
case Some(u) => Ok(u)
}
}
val createUser: Endpoint[User] = post("users" :: userReqParams) { p: UserForm =>
(for {
id <- User.create(p.email, p.screen_name)
user <- User.find(id)
} yield user) map {
case Some(u) => Created(u)
case _ => NotFound(new Exception("Record Not Found"))
}
}
// 配列jsonも出来るかな
val createUserByJson: Endpoint[Int] = post("usersjson" :: userJson) { p: Seq[UserForm] =>
val insertedId = p.map(a => User.create(a.email, a.screen_name))
Ok(insertedId.size)
}
val userService: Service[Request, Response] = ( listUser :+: showUser :+: createUser :+: createUserByJson)
.handle{
case fe: io.finch.Error => BadRequest(new Exception(fe.getMessage)) // validation Error が起きた場合のcase
case e: Exception => InternalServerError(new Exception(e.getMessage))
}
.toServiceAs[Application.Json]
def main(args: Array[String]): Unit = {
Await.ready(Http.serve(":8082", userService))
}
}
なんか以下のエラーが出た。どうやら、レスポンス時にしっかりとエンコーディングしているかどうかをコンパイル時にチェッックしてくれるらしい。。
error: An Endpoint you're trying to convert into a Finagle service is missing one or more encoders
インポート文を追加したら解消された。
import io.circe.generic.auto._ // *
import io.finch.circe._ // *
どうやら、implicit def encodeCirce を toServiceAsメソッドに暗黙渡しをしないとダメみだいだ。
Main.scala
// 配列jsonも出来るかな
val createUserByJson: Endpoint[Int] = post("usersjson" :: userJson) { p: Seq[UserForm] =>
val insertedId = p.map(a => User.create(a.email, a.screen_name))
Ok(insertedId.size)
}
curl
// 以下のcurlコマンドで、配列jsonも登録できた。
curl -d '[{"email":"eee1@com","screen_name":"test1"},{"email":"eef@ssl","screen_name":"test223"}]' -H "Content-Type: application/json" -X POST http://localhost:8082/usersjson
UserForm.scala
package jp.co.finchitest.forms
import io.finch.{Endpoint, ValidationRule, param}
// formにemail validation機能を付与してみました
case class UserForm(email: String, screen_name: String)
object UserForm {
val mailRule = ValidationRule[String]("mail should be mailRule")(a => """(\w+)@([\w\.]+)""".r.unapplySeq(a).isDefined)
val userReqParams:Endpoint[UserForm]= (
param("email").should(mailRule) ::
param("screen_name")
).as[UserForm]
val userJson:Endpoint[Seq[UserForm]] = jsonBody[Seq[UserForm]]
}
MysqlHelper.scala
package jp.co.finchitest.helpers
import com.twitter.finagle.Mysql
//WebアプリらしくDB環境周りは独立してみました。
object MysqlHelper {
implicit val client = Mysql.client
.withCredentials("root", null)
.withDatabase("nano_planner_dev")
.newRichClient("127.0.0.1:3306")
}
User.scala
リンク:Finch + MySQLでREST APIサーバを構築する のコードから変えておりません
参考リンク:finchについての情報を一切持ってないので、参考にさせて頂きました。大変助かりました。ありがとうございます。
Finch + MySQLでREST APIサーバを構築する
finch触ってみた
finch公式サイト