play フレームワークに基づく json rest api アプリケーションがあり、着信要求を解析するときに検証エラーに関する情報を受け取りたいと考えています。json 配列から json 値への変換を除いて、すべて正常に動作しています。私が達成したいJson構造:
{
"errors": {
"name": ["invalid", "tooshort"],
"email": ["invalid"]
}
}
サンプルを実装しようとすると、完全に機能しました。
def error = Action {
BadRequest(obj(
"errors" -> obj(
"name" -> arr("invalid", "tooshort"),
"email" -> arr("invalid")
)
))
}
このように変化部分を抽出しようとすると:
def error = Action {
val e = Seq("name" -> arr("invalid", "tooshort"), "email" -> arr("invalid"))
// in real app it will be Seq[(JsPath, Seq[ValidationError])]
BadRequest(obj(
"errors" -> obj(e: _*)
))
}
コンパイラ エラーが発生しました。
型の不一致; 見つかった: Seq[(String, play.api.libs.json.JsArray)] 必須: Seq[(String, play.api.libs.json.Json.JsValueWrapper)]
JsArray から JsValueWrapper への暗黙の変換が欠けているのではないでしょうか? しかし、なぜサンプルは同じファイルで同じインポートで正常に動作するのでしょうか?
Play 2.1.1、Scala 2.10.0
更新: 最終コードの Julien Lafont のおかげで問題が解決しました:
implicit val errorsWrites = new Writes[Seq[(JsPath, Seq[ValidationError])]] {
/**
* Maps validation result of Ember.js json request to json validation object, which Ember can understand and parse as DS.Model 'errors' field.
*
* @param errors errors collected after json validation
* @return json in following format:
*
* {
* "errors": {
* "error1": ["message1", "message2", ...],
* "error2": ["message3", "message4", ...],
* ...
* }
* }
*/
def writes(errors: Seq[(JsPath, Seq[ValidationError])]) = {
val mappedErrors = errors.map {
e =>
val fieldName = e._1.toString().split("/").last // take only last part of the path, which contains real field name
val messages = e._2.map(_.message)
fieldName -> messages
}
obj("errors" -> toJson(mappedErrors.toMap)) // Ember requires root "errors" object
}
}
使用法:
def create = Action(parse.json) { // method in play controller
request =>
fromJson(request.body) match {
case JsSuccess(pet, path) => Ok(obj("pet" -> Pets.create(pet)))
case JsError(errors) => UnprocessableEntity(toJson(errors)) // Ember.js expects 422 error code in case of errors
}
}