Documentation

You are viewing the documentation for the 2.1.x release series. The latest stable release series is 2.4.x.

§JSON リクエストとレスポンス

§JSON リクエストの処理

JSON リクエストは JSON データをリクエストボディに含む HTTP リクエストです。JSON リクエストは、Content-Type ヘッダに text/jsonapplication/json という MIME タイプを指定する必要があります。

Actionany content ボディパーサーをデフォルトで使います。これを利用して、リクエストボディを JSON (具体的には、JsValue) として取得することができます。

package controllers

import play.api._
import play.api.mvc._
import play.api.libs.json._
// you need this import to have combinators
import play.api.libs.functional.syntax._

object Application extends Controller {
  
  implicit val rds = (
    (__ \ 'name).read[String] and
    (__ \ 'age).read[Long]
  ) tupled

  def sayHello = Action { request =>
    request.body.asJson.map { json =>
      json.validate[(String, Long)].map{ 
        case (name, age) => Ok("Hello " + name + ", you're "+age)
      }.recoverTotal{
        e => BadRequest("Detected error:"+ JsError.toFlatJson(e))
      }
    }.getOrElse {
      BadRequest("Expecting Json data")
    }
  }
}

この場合、専用の BodyParser を指定することで Play にコンテントボディを直接的に JSON としてパースさせると、記述がシンプル化されてなお良いでしょう。

  def sayHello = Action(parse.json) { request =>
    request.body.validate[(String, Long)].map{ 
      case (name, age) => Ok("Hello " + name + ", you're "+age)
    }.recoverTotal{
      e => BadRequest("Detected error:"+ JsError.toFlatJson(e))
    }
  }

Note: JSON ボディパーサーを利用すると、request.body の値が直接 JsValue として扱えるようになります。

注意:

§implicits Reads[(String, Long)]

入力された JSON のバリデーションと変換を行うことのできるコンビネータを使う、暗黙の Reads を定義します。

§json.validate[(String, Long)]

暗黙の Reads[(String, Long)] に従って、入力された JSON のバリデーションと変換を明示的に行います。

このアクションは、コマンドラインから cURL を使って以下のようにテストできます。

§json.validate[(String, Long)].map{ (String, Long) => ... }

JSON の変換に成功した場合、その結果をアクションの結果にマップします。

§json.validate[(String, Long)].recoverTotal{ e: JsError => ... }

recoverTotal は、発生したエラーに対応して、デフォルト値を返す関数を受け取ります:
- JsResult の変更チェーンを終了し、正常に作成された内部文字列を返します
- または、失敗を検出した場合は recoverToal に渡された関数の実行結果を返します。

§JsError.toFlatJson(e)

JsError を平べったい JsObject 形式に変換するヘルパーです :

JsError(List((/age,List(ValidationError(validate.error.missing-path,WrappedArray()))), (/name,List(ValidationError(validate.error.missing-path,WrappedArray())))))

これは、次のような JsValue になります:

{"obj.age":[{"msg":"validate.error.missing-path","args":[]}],"obj.name":[{"msg":"validate.error.missing-path","args":[]}]}

今後、この他にもいくつかのヘルパーが提供される予定です。

試してみましょう

§成功した場合

curl 
  --header "Content-type: application/json" 
  --request POST 
  --data '{"name": "Toto", "age": 32}' 
  http://localhost:9000/sayHello

レスポンスは以下のようになります。

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 47

Hello Toto, you're 32

§失敗した場合 “見つからない JSON フィールド”

curl 
  --header "Content-type: application/json" 
  --request POST 
  --data '{"name2": "Toto", "age2": 32}' 
  http://localhost:9000/sayHello

レスポンスは以下のようになります。

HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Content-Length: 106

Detected error:{"obj.age":[{"msg":"validate.error.missing-path","args":[]}],"obj.name":[{"msg":"validate.error.missing-path","args":[]}]}

§失敗した場合 “不正な JSON 型”

curl 
  --header "Content-type: application/json" 
  --request POST 
  --data '{"name": "Toto", "age": "chboing"}' 
  http://localhost:9000/sayHello

レスポンスは以下のようになります。

HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Content-Length: 100

Detected error:{"obj.age":[{"msg":"validate.error.expected.jsnumber","args":[]}]}

§JSON レスポンスの送信

前述の例ではリクエストを JSON で受けていましたが、レスポンスは text/plain として送信していました。これを、正しい JSON HTTP レスポンスを送り返すように変更してみましょう。

  def sayHello = Action(parse.json) { request =>
    request.body.validate[(String, Long)].map{ 
      case (name, age) => Ok(Json.obj("status" ->"OK", "message" -> ("Hello "+name+" , you're "+age) ))
    }.recoverTotal{
      e => BadRequest(Json.obj("status" ->"KO", "message" -> JsError.toFlatJson(e)))
    }
  }

レスポンスは以下のようになります。

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 47

{"status":"OK","message":"Hello Toto, you're 32"}

§JSON を直接返す

Play 2.1 と JSON で Todo リストを返すのはとても簡単です:

import play.api.libs.json.Json

def tasksAsJson() = Action {
  Ok(Json.toJson(Task.all().map { t=>
    (t.id.toString, t.label)
  } toMap))
}

次ページ: XML


このドキュメントの翻訳は Play チームによってメンテナンスされているものではありません。 間違いを見つけた場合、このページのソースコードを ここ で確認することができます。 ドキュメントガイドライン を読んで、お気軽にプルリクエストを送ってください。