Purpose
Even if the the @martin's answer is giving the straight solution regarding the mismatch between the json message and the expected result, I'd like to give you some advices for a clean way to reach your goal.
That's because, AFAICK, you're redefining way too much things and you could meet cases where errors aren't reported... but just hidden by a different error like NoSuchElementException.
Lastly, I would like to give a solution where your message is kept unchanged (like the second @Martin 's solution was).
Proposition
The idea is to keep things packaged with their responsibilities also the code is split in three different files:
FBUser.scala
which simply declares the model structure
package models
case class FBUser(
name: String,
id: String
)
formats.scala
which is a package that will gather all formats definition, specially the json ones:
package models
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.json.util._
import play.api.libs.json.Json._
import play.api.libs.functional.syntax._
package formats {
object jsons {
implicit val fbUserFormat:Format[FBUser] = Json.format[FBUser]
}
}
Note that the format for List[FBUser]
is not provided because the json api will resolve to the implicit and generic Reads
and OWrites
.
And lastly, the Application.scala
that will contain code only relevant to some use cases, like the json object containing a data
field, the list of FBUser
.
package controllers
import play.api._
import play.api.mvc._
import play.api.libs.json._
import play.api.libs.json.Json._
import models._
object Application extends Controller {
import models.formats.jsons._
val readUserFromInput = (__ 'data).read[List[FBUser]]
def index = Action {
val jsonString = "{"data": [{"name": "Me Lazyan","id": "1182"},{"name": "Chales Dselle","id": "10115"},{"name": "Be My","id": "10275"},{"name": "De Rwani", "id": "11189"},{"name": "Phoe Johon", "id": "11372"}]}"
val json = Json.parse(jsonString)
val users = json.validate(readUserFromInput)
users.map(
list => Ok(Json.toJson(list)) // or Ok(json) to match exactly you example
).recoverTotal{
err => BadRequest(JsError.toFlatJson(err))
}
}
}
In this controller, we can see that it defines the specific Reads
for the initial case, thus the access to the data field and the reads to FBUser
instance are safe thanks to the use of validate
, map
and recoverTotal
.
Some words
A last note about safety, Json.parse
is not safe so in order to be even more safe you should consider some options depending on your workflows, some of them are:
* using the json body parser that'll let you handle bad json format explicitly
* using a dedicated case class defined in the controller for this particular case (and then define its Reads/... using inception like for FBUser
)