I am writing a Play 2.3 application that serves JSON backed by mongodb. Some of the documents coming from the database contain sensitive fields. I want to be able to work with these documents server side but send a limited JSON view to clients. The documentation on Reads/Writes combinators discusses defining implicit Reads and Writes which works fine for sending data to and from the database but does not completely fill my needs.
What I want to do is define any number of additional Writes that I can use like json "views" to send particular transformations or subsets of models to clients. In Rails I use JBuilder for this purpose.
Trying to explicitly pass a different Writes to toJson
does not give me the expected behavior. Take this simple controller action which should write a JSON array of all user ids and usernames:
def listUsers = Action.async {
val testCustomWrite: Writes[User] = (
(__ \ "id").write[String] and
(__ \ "username").write[String]) { user: User =>
(user._id.toString(), user.username)
}
UserDao.findAll().map {
case Nil => Ok(Json.toJson(""))
case users => Ok(Json.toJson(users)(testCustomWrite))
}
}
This fails to compile with
type mismatch;
[error] found : play.api.libs.json.Writes[models.User]
[error] required: play.api.libs.json.Writes[List[models.User]]
[error] case users => Ok(Json.toJson(users)(testCustomWrite))
The way toJson
handles writing a list of objects depends on an implicit writer for arrays which depends on an implicit writer for a type. I could rewrite the above to to be val testCustomWrite: Writes[List[User]]
but that does not feel like the correct solution because Play already provides an array wrapper for implicit writes.
Is there a preferred way to render multiple JSON "views" in Play2?
When passing the Writes
explicitly, the type has to match. In this case you can use Writes.list
:
Json.toJson(users)(Writes.list(testCustomWrite))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With