はじめに
私は Action で Request Body の JSON からクラスにマッピングする、といった処理を良く書きます。
Action 内のコードでパースすることもできますが、 Play の機能を上手く使えば簡潔に書けるので、その方法をご紹介します。
問題のコード
素直に書くとこのような感じになります。
class MyController extends InjectedController {
case class MyRequestBody(foo: String)
implicit val myReads: Reads[MyRequestBody] = Json.reads[MyRequestBody]
def myAction = Action { request =>
request.body.asJson match {
case None => UnsupportedMediaType
case Some(json) => json.validate[MyRequestBody] match {
case _: JsError => BadRequest
case JsSuccess(body, _) =>
// some process
Ok
}
}
}
}
Request Body が Json でなければ Unsupported Media Type 、Json を クラスにマッピングできなければ Bad Request を返す、というコードです。
一度だけならあまり問題にはなりませんが、毎回書くとなるとかなり煩わしいです。
改善後のコード
parse.json[A](implicit reader: Reads[A])
を使うことで、 Action の実行前にパースします。
class MyController extends InjectedController {
case class MyRequestBody(foo: String)
implicit val myReads: Reads[MyRequestBody] = Json.reads[MyRequestBody]
def myAction: Action[MyRequestBody] = Action(parse.json[MyRequestBody]) { request =>
val body: MyRequestBody = request.body
// some process
Ok
}
}
かなり簡潔になったのではないでしょうか。
このコードでも前のコードと同様に Unsupported Media Type と Bad Request を返せます。
おわりに
Action の実行前に Request Body をパースする方法をご紹介しました。
仕様によって細かく分岐させなければいけない場合などもありますので、いつでも使えるわけではありませんが、多くのケースに適用できるのではないでしょうか。
是非使ってみてください。