Help us understand the problem. What is going on with this article?

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

}

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away