JSON投げの標的サーバーを作りたいです。でもパース面倒くさいです。
Play Framework Json case class
あたりで検索すると参考になる記事がたくさん出てくるんですが、なんだかどれも今ひとつ簡単に思えないのです。いちいちAPIごとにクラス作るのはいいとして、どうせ1回くらいしか使わないのに毎回implicitを書くんですよね… お辛い… みたいな。
関連処理ごとどこかに隠蔽しようかなあとも思ったんですが(先送り体質)、それだと「どういうJSONを投げなきゃいけないのか」がコードから読み取れなくなりますので、逆に困ります。
とはいえ、リクエストの内容がおかしかったら場合分けしたいし、やりたいことはそれなりにあるので毎回書くのはやっぱり嫌。
というわけで関数を悪魔合体させて何とかします。Tryはおまけです。
ApiController.scala
trait ApiController extends Controller {
def TryJsonAction[T](r: Reads[T])(act: T => Request[AnyContent] => Result): Action[AnyContent] = Action { request =>
request.body.asJson.flatMap(_.asOpt[T](r)) match {
case None => BadRequest
case Some(apiValue) => Try { act(apiValue)(request) } match {
case Success(result) => result
case Failure(_) => InternalServerError
}
}
}
def TryAction[T](act: Request[AnyContent] => Result): Action[AnyContent] = Action { request =>
Try (act(request)) match {
case Success(result) => result
case Failure(_) => InternalServerError
}
}
def TryAction[T](act: => Result): Action[AnyContent] = TryAction(_ => act)
}
使うときはこんな感じ。daoは適当、イメージです。
server.scala
class Server @Inject()(dao: WorkerDao) extends ApiController {
case class CreateWorkerApiValue(name: String)
def createWorker = TryJsonAction(Json.reads[CreateWorkerApiValue]) { apiValue => request =>
Ok(dao.generate(apiValue.name).register.toJson)
}
}
結構スッキリしましたね。多分動くんじゃないかなと思われます。