Books

Please note this documentation was initially published as an article by Pascal Voitot (@mandubian) on mandubian.com

Now you should know how to validate JSON and convert into any structure you can write in Scala and back to JSON. But as soon as I’ve begun to use those combinators to write web applications, I almost immediately encountered a case : read JSON from network, validate it and convert it into… JSON.

For a few years now, in almost all web frameworks (except recent JS serverside stuff maybe in which JSON is the default data structure), we have been used to get JSON from network and convert JSON (or even POST/GET data) into OO structures such as classes (or case classes in Scala). Why?

for a good reason : OO structures are “language-native” and allows manipulating data with respect to your business logic in a seamless way while ensuring isolation of business logic from web layers.

for a more questionable reason : ORM frameworks talk to DB only with OO structures and we have (kind of) convinced ourselves that it was impossible to do else… with the well-known good & bad features of ORMs… (not here to criticize those stuff)

Besides this fact, we have some new DB types such as Mongo (or CouchDB) accepting document structured data looking almost like JSON trees (_isn’t BSON, Binary JSON?_).With these DB types, we also have new great tools such as ReactiveMongo which provides reactive environment to stream data to and from Mongo in a very natural way.I’ve been working with Stephane Godbillon to integrate ReactiveMongo with Play2.1 while writing the Play2-ReactiveMongo module. Besides Mongo facilities for Play2.1, this module provides Json To/From BSON conversion typeclasses.

So it means you can manipulate JSON flows to and from DB directly without even converting into OO.

filter/transform this JSON to send only mandatory data in the format expected by the client (for ex, you don’t want some secure info to go out),

directly send JSON to the client

In this context, we can easily imagine manipulating a flow of JSON data from client to DB and back without any (explicit) transformation in anything else than JSON.Naturally, when you plug this transformation flow on reactive infrastructure provided by Play2.1, it suddenly opens new horizons.

This is the so-called (by me) JSON coast-to-coast design:

Don’t consider JSON data chunk by chunk but as a continuous flow of data from client to DB (or else) through server,

Treat the JSON flow like a pipe that you connect to others pipes while applying modifications, transformations alongside,

Treat the flow in a fully asynchronous/non-blocking way.

This is also one of the reason of being of Play2.1 reactive architecture…I believe considering your app through the prism of flows of data changes drastically the way you design your web apps in general. It may also open new functional scopes that fit today’s webapps requirements quite better than classic architecture. Anyway, this is not the subject here ;)

So, as you have deduced by yourself, to be able to manipulate Json flows based on validation and transformation directly, we needed some new tools. JSON combinators were good candidates but they are a bit too generic.That’s why we have created some specialized combinators and API called JSON transformers to do that.

You may tell JSON transformers are just f:JSON => JSON.So a JSON transformer could be simply a Writes[A <: JsValue].But, a JSON transformer is not only a function: as we said, we also want to validate JSON while transforming it.As a consequence, a JSON transformer is a Reads[A <: Jsvalue].

Keep in mind that a Reads[A <: JsValue] is able to transform and not only to read/validate

removes given JsPath from input JSON (key22 has disappeared under key2)

Please note the resulting JsObject hasn’t same keys order as input JsObject. This is due to the implementation of JsObject and to the merge mechanism. But this is not important since we have overriden JsObject.equals method to take this into account.

Reminder:jsPath.json.prune only works with JsObject and removes given JsPath form input JSON)

Please note that:- prune doesn’t work for recursive JsPath for the time being- if prune doesn’t find any branch to delete, it doesn’t generate any error and returns unchanged JSON.

Just keep in mind that you have now a huge toolkit to create generic JSON transformers.You can compose, map, flatmap transformers together into other transformers. So possibilities are almost infinite.

But there is a final point to treat: mixing those great new JSON transformers with previously presented Reads combinators.This is quite trivial as JSON transformers are just Reads[A <: JsValue]