5

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?

1 Answer 1

7

When passing the Writes explicitly, the type has to match. In this case you can use Writes.list:

Json.toJson(users)(Writes.list(testCustomWrite))
Sign up to request clarification or add additional context in comments.

2 Comments

Ah, thank you. I am still pretty new to scala so I missed that. In your opinion is having several different Writes in order to define JSON "views" on a model the best/standard pattern in Play2?
@imagio I usually don't have multiple reads/writes per class, but sometimes it's necessary. For example, if one needs to have some information pruned from it before being serialized, or perhaps extra information added.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.