Edited at

Play Framework サーバーでJSONを拾ってリアクションする手短な書き方

More than 3 years have passed since last update.

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)
}

}


結構スッキリしましたね。多分動くんじゃないかなと思われます。