In Part 1 and Part 2 , we have presented Json combinators for Reads[T], Writes[T] and Format[T]. So 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.



Introducing JSON coast-to-coast design

Are we doomed to convert JSON to OO?

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)

Is OO conversion really the default usecase?

In many cases, you don’t really need to perform any real business logic with data but validating/transforming before storing or after extracting.

Let’s take the CRUD case:

  • You just get the data from the network, validate them a bit and insert/update into DB.
  • In the other way, you just retrieve data from DB and send them outside.

So, generally, for CRUD ops, you convert JSON into a OO structure just because the frameworks are only able to speak OO.

I don’t say or pretend you shouldn’t use JSON to OO conversion but maybe this is not the most common case and we should keep conversion to OO only when we have real business logic to fulfill.

New tech players change the way of manipulating JSON

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.

JSON coast-to-coast design

Taking this into account, we can easily imagine the following:

  • receive JSON,
  • validate JSON,
  • transform JSON to fit expected DB document structure,
  • directly send JSON to DB (or somewhere else)

This is exactly the same case when serving data from DB:

  • extract some data from DB as JSON directly,
  • 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.



JSON transformers are Reads[T <: JsValue]

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



Recent Play2 JSON syntax evolutions

As you know, Json API for Play2.1 was still draft and has evolved since I began writing article part 1/2.
We have changed a few things since (nothing conceptual, just cosmetics).

Syntax clarification

Reads[A] andThen Reads[B] has been renamed Reads[A] andKeep Reads[B] (keep the right side result)

Reads[A] provided Reads[B] has been renamed Reads[A] keepAnd Reads[B] (keep the left side result and is symmetric with andKeep)

Remarkable new Reads[A] features

Reads[A <: JsValue] andThen Reads[B]

andThen has the classic Scala semantic of function composition : it applies Reads[A <: JsValue] on JSON retrieving a JsValue and then applies Reads[B] on this JsValue.


Reads[A <: JsValue].map(f: A => B): Reads[B]

map is the classic and always very useful Scala map function.


Reads[A <: JsValue].flatMap(f: A => Reads[B]): Reads[B]

flatMap is the classic Scala flatMap function.



JSON transformers case by case

A few reminders

JSON new syntax

In code samples, we’ll use the following JSON.

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "key1" : "value1",
  "key2" : {
    "key21" : 123,
    "key22" : true,
    "key23" : [ "alpha", "beta", "gamma"]
    "key24" : {
      "key241" : 234.123,
      "key242" : "value242"
    }
  },
  "key3" : 234
}

Remind that, in Play2, you can write this JSON as following.

1
2
3
4
5
6
7
8
9
10
11
12
13
val json = Json.obj(
  "key1" -> "value1",
  "key2" -> Json.obj(
    "key21" -> 123,
    "key22" -> true,
    "key23" -> Json.arr("alpha", "beta", "gamma"),
    "key24" -> Json.obj(
      "key241" -> 234.123,
      "key242" -> "value242"
    )
  ),
  "key3" -> 234
)

Defining Play2 JSON action controller

Here is how you would write a Play2.1 action controller to receive and manipulate/validate JSON.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
object YourController {
  

  // not implicit because I want to control which transformer I use
  val jsonTransformer: Reads[JsValue] = 

  def doit = Action(parse.json) { request =>
      request.body.validate(jsonTransformer).map { js =>
          // do something
          Ok(...)  
      }.recover { error =>
          BadRequest()
          }
  }
  
  
}

Please note the JsResult.map and JsResult.recover functions allowing to compose result and deal with errors.

Now let’s describe JSON transformers with samples

Case 1: Pick JSON value in JsPath

Pick value as JsValue

1
2
3
4
5
6
7
8
9
10
import play.api.libs.json._

val jsonTransformer = (__ \ 'key2 \ 'key23).json.pick

scala> json.validate(jsonTransformer)
res9: play.api.libs.json.JsResult[play.api.libs.json.JsValue] =
  JsSuccess(
    ["alpha","beta","gamma"],
    /key2/key23
  )
(__ \ 'key2 \ 'key23).json...
  • All JSON transformers are in JsPath.json.
(__ \ 'key2 \ 'key23).json.pick
  • pick is a Reads[JsValue] which picks the value IN the given JsPath. Here ["alpha","beta","gamma"]
JsSuccess(["alpha","beta","gamma"],/key2/key23)
  • This is a simply successful JsResult
  • For info, /key2/key23 represents the JsPath where data were read but don’t care about it, it’s mainly used by Play API to compose JsResult(s))
  • ["alpha","beta","gamma"] is just due to the fact that we have overriden toString

To Remember jsPath.json.pick gets ONLY the value inside the JsPath


Pick value as Type

1
2
3
4
5
6
7
8
9
10
import play.api.libs.json._

val jsonTransformer = (__ \ 'key2 \ 'key23).json.pick[JsArray]

scala> json.validate(jsonTransformer)
res10: play.api.libs.json.JsResult[play.api.libs.json.JsArray] =
  JsSuccess(
    ["alpha","beta","gamma"],
    /key2/key23
  )
(__ \ 'key2 \ 'key23).json.pick[JsArray]
  • pick[T] is a Reads[T <: JsValue] which picks the value (as a JsArray in our case) IN the given JsPath

To Remember: jsPath.json.pick[T <: JsValue] extracts ONLY the typed value inside the JsPath


Case 2: Pick branch following JsPath

Pick branch as JsValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import play.api.libs.json._

val jsonTransformer = (__ \ 'key2 \ 'key24 \ 'key241).json.pickBranch

scala> json.validate(jsonTransformer)
res11: play.api.libs.json.JsResult[play.api.libs.json.JsObject] =
  JsSuccess(
  {
    "key2": {
      "key24":{
        "key241":234.123
      }
    }
  },
  /key2/key24/key241
  )
(__ \ 'key2 \ 'key23).json.pickBranch
  • pickBranch is a Reads[JsValue] which picks the branch from root to given JsPath
{"key2":{"key24":{"key242":"value242"}}}
  • The result is the branch from root to given JsPath including the JsValue in JsPath

To Remember: jsPath.json.pickBranch extracts the single branch down to JsPath + the value inside JsPath


Case 3: Copy a value from input JsPath into a new JsPath

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import play.api.libs.json._

val jsonTransformer = (__ \ 'key25 \ 'key251).json.copyFrom( (__ \ 'key2 \ 'key21).json.pick )

scala> json.validate(jsonTransformer)
res12: play.api.libs.json.JsResult[play.api.libs.json.JsObject]
  JsSuccess(
    {
      "key25":{
        "key251":123
      }
    },
    /key2/key21
  )
(__ \ 'key25 \ 'key251).json.copyFrom( reads: Reads[A <: JsValue] )
  • copyFrom is a Reads[JsValue]
  • copyFrom reads the JsValue from input JSON using provided Reads[A]
  • copyFrom copies this extracted JsValue as the leaf of a new branch corresponding to given JsPath
{"key25":{"key251":123}}
  • copyFrom reads value 123
  • copyFrom copies this value into new branch (__ \ 'key25 \ 'key251)

To Remember: jsPath.json.copyFrom(Reads[A <: JsValue]) reads value from input JSON and creates a new branch with result as leaf


Case 4: Copy full input Json & update a branch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import play.api.libs.json._

val jsonTransformer = (__ \ 'key2 \ 'key24).json.update(
  __.read[JsObject].map{ o => o ++ Json.obj( "field243" -> "coucou" ) }
)

scala> json.validate(jsonTransformer)
res13: play.api.libs.json.JsResult[play.api.libs.json.JsObject] =
  JsSuccess(
    {
      "key1":"value1",
      "key2":{
        "key21":123,
        "key22":true,
        "key23":["alpha","beta","gamma"],
        "key24":{
          "key241":234.123,
          "key242":"value242",
          "field243":"coucou"
        }
      },
      "key3":234
    },
  )
(__ \ 'key2).json.update(reads: Reads[A < JsValue])
  • is a Reads[JsObject]
(__ \ 'key2 \ 'key24).json.update(reads) does 3 things:
  • extracts value from input JSON at JsPath (__ \ 'key2 \ 'key24)
  • applies reads on this relative value and re-creates a branch (__ \ 'key2 \ 'key24) adding result of reads as leaf
  • merges this branch with full input JSON replacing existing branch (so it works only with input JsObject and not other type of JsValue)
JsSuccess({…},)
  • Just for info, there is no JsPath as 2nd parameter there because the JSON manipulation was done from Root JsPath

To Remember: jsPath.json.update(Reads[A <: JsValue]) only works for JsObject, copies full input JsObject and updates jsPath with provided Reads[A <: JsValue]


Case 5: Put a given value in a new branch

1
2
3
4
5
6
7
8
9
10
11
12
13
import play.api.libs.json._

val jsonTransformer = (__ \ 'key24 \ 'key241).json.put(JsNumber(456))

scala> json.validate(jsonTransformer)
res14: play.api.libs.json.JsResult[play.api.libs.json.JsObject] =
  JsSuccess(
    {
      "key24":{
        "key241":456
      }
    },
  )
(__ \ 'key24 \ 'key241).json.put( a: => JsValue )
  • is a Reads[JsObject]
(__ \ 'key24 \ 'key241).json.put( a: => JsValue )
  • creates a new branch (__ \ 'key24 \ 'key241)
  • puts a as leaf of this branch.
jsPath.json.put( a: => JsValue )
  • takes a JsValue argument passed by name allowing to pass even a closure to it.
jsPath.json.put
  • doesn’t care at all about input JSON
  • simply replace input JSON by given value

To Remember: jsPath.json.put( a: => Jsvalue ) creates a new branch with a given value without taking into account input JSON


Case 6: Prune a branch from input JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import play.api.libs.json._

val jsonTransformer = (__ \ 'key2 \ 'key22).json.prune

scala> json.validate(jsonTransformer)
res15: play.api.libs.json.JsResult[play.api.libs.json.JsObject] =
  JsSuccess(
    {
      "key1":"value1",
      "key3":234,
      "key2":{
        "key21":123,
        "key23":["alpha","beta","gamma"],
        "key24":{
          "key241":234.123,
          "key242":"value242"
        }
      }
    },
    /key2/key22/key22
  )
(__ \ 'key2 \ 'key22).json.prune
  • is a Reads[JsObject] that works only with JsObject
(__ \ 'key2 \ 'key22).json.prune
  • 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.

To Remember: 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.

More complicated cases

Case 7: Pick a branch and update its content in 2 places

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import play.api.libs.json._
import play.api.libs.json.Reads._

val jsonTransformer = (__ \ 'key2).json.pickBranch(
  (__ \ 'key21).json.update(
    of[JsNumber].map{ case JsNumber(nb) => JsNumber(nb + 10) }
  ) andThen
  (__ \ 'key23).json.update(
    of[JsArray].map{ case JsArray(arr) => JsArray(arr :+ JsString("delta")) }
  )
)

scala> json.validate(jsonTransformer)
res16: play.api.libs.json.JsResult[play.api.libs.json.JsObject] =
  JsSuccess(
    {
      "key2":{
        "key21":133,
        "key22":true,
        "key23":["alpha","beta","gamma","delta"],
        "key24":{
          "key241":234.123,
          "key242":"value242"
        }
      }
    },
    /key2
  )
(__ \ 'key2).json.pickBranch(reads: Reads[A <: JsValue])
  • extracts branch __ \ 'key2 from input JSON and applies reads to the relative leaf of this branch (only to the content)
(__ \ 'key21).json.update(reads: Reads[A <: JsValue])
  • updates (__ \ 'key21) branch
of[JsNumber]
  • is just a Reads[JsNumber]
  • extracts a JsNumber from (__ \ 'key21)
of[JsNumber].map{ case JsNumber(nb) => JsNumber(nb + 10) }
  • reads a JsNumber (value 123 in __ \ 'key21)
  • uses Reads[A].map to increase it by 10 (in immutable way naturally)
andThen
  • is just the composition of 2 Reads[A]
  • first reads is applied and then result is piped to second reads
of[JsArray].map{ case JsArray(arr) => JsArray(arr :+ JsString("delta")
  • reads a JsArray (value [alpha, beta, gamma] in __ \ 'key23)
  • uses Reads[A].map to append JsString("delta") to it

Please note the result is just the __ \ 'key2 branch since we picked only this branch


Case 8: Pick a branch and prune a sub-branch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import play.api.libs.json._
import play.api.libs.json.Reads._

val jsonTransformer = (__ \ 'key2).json.pickBranch(
  (__ \ 'key23).json.prune
)

scala> json.validate(jsonTransformer)
res18: play.api.libs.json.JsResult[play.api.libs.json.JsObject] =
  JsSuccess(
    {
      "key2":{
        "key21":123,
        "key22":true,
        "key24":{
          "key241":234.123,
          "key242":"value242"
        }
      }
    },
    /key2/key23
  )
(__ \ 'key2).json.pickBranch(reads: Reads[A <: JsValue])
  • extracts branch __ \ 'key2 from input JSON and applies reads to the relative leaf of this branch (only to the content)
(__ \ 'key23).json.prune
  • removes branch __ \ 'key23 from relative JSON

Please remark the result is just the __ \ 'key2 branch without key23 field.

What about combinators?

I stop there before it becomes boring (if not yet)…

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]

Let’s demonstrate by writing a Gizmo to Gremlin JSON transformer.

Here is Gizmo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val gizmo = Json.obj(
  "name" -> "gizmo",
  "description" -> Json.obj(
      "features" -> Json.arr( "hairy", "cute", "gentle"),
      "size" -> 10,
      "sex" -> "undefined",
      "life_expectancy" -> "very old",
      "danger" -> Json.obj(
          "wet" -> "multiplies",
          "feed after midnight" -> "becomes gremlin"
      )
  ),
  "loves" -> "all"
)

Here is Gremlin:

1
2
3
4
5
6
7
8
9
10
11
val gremlin = Json.obj(
  "name" -> "gremlin",
  "description" -> Json.obj(
      "features" -> Json.arr("skinny", "ugly", "evil"),
      "size" -> 30,
      "sex" -> "undefined",
      "life_expectancy" -> "very old",
      "danger" -> "always"
  ),
  "hates" -> "all"
)

Ok let’s write a JSON transformer to do this transformation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.json.util._

val gizmo2gremlin = (
  (__ \ 'name).json.put(JsString("gremlin")) and
  (__ \ 'description).json.pickBranch(
      (__ \ 'size).json.update( of[JsNumber].map{ case JsNumber(size) => JsNumber(size * 3) } ) and
      (__ \ 'features).json.put( Json.arr("skinny", "ugly", "evil") ) and
      (__ \ 'danger).json.put(JsString("always"))
      reduce
  ) and
  (__ \ 'hates).json.copyFrom( (__ \ 'loves).json.pick )
) reduce

scala> gizmo.validate(gizmo2gremlin)
res22: play.api.libs.json.JsResult[play.api.libs.json.JsObject] =
  JsSuccess(
    {
      "name":"gremlin",
      "description":{
        "features":["skinny","ugly","evil"],
        "size":30,
        "sex":"undefined",
        "life_expectancy":
        "very old","danger":"always"
      },
      "hates":"all"
    },
  )

Here we are ;)
I’m not going to explain all of this because you should be able to understand now.
Just remark:

(__ \ 'features).json.put(…) is after (__ \ 'size).json.update so that it overwrites original (__ \ 'features)

(Reads[JsObject] and Reads[JsObject]) reduce
  • It merges results of both Reads[JsObject] (JsObject ++ JsObject)
  • It also applies the same JSON to both Reads[JsObject] unlike andThen which injects the result of the first reads into second one.


Conclusion

After 3 long articles, I think we have done a full 360° around new features brought by Play2.1 JSON API.
I hope you glimpse the whole new world of possiblities it can bring to us.
Personnally, I’ve begun using it in projects and I don’t yet see the limits of it and how I’ll end using it.

The only thing I can say is that it has changed my way of manipulating JSON data flows in general.

Next article coming soon: an applied example of a webapp following Json coast-to-coast design with ReactiveMongo

Have fun ;););)

In Part 1 article, we gave a quick overview of new Play2.1 JSON API features around JsPath and Reads combinators. It’s funny to be able to read JSON to Scala structures but it’s better to be able to write Scala structures to JSON (Writes[T]) and it’s even better to mix Reads and Writes (Format[T]) sometimes.

Now let’s focus on Writes and Format in the details ;)



Writes[T] hasn’t changed (except combinators)

Writes in Play2.0.x

Do you remember how you had to write a Json Writes[T] in Play2.0.x ?
You had to override the writes function.

1
2
3
4
5
6
7
trait Writes[-A] {
  self =>
  /**
   * Convert the object into a JsValue
   */
  def writes(o: A): JsValue
}

Take the same simple case class we used in Part 1:

1
2
3
4
5
case class Creature(
  name: String,
  isDead: Boolean,
  weight: Float
)

In Play2.0.x, you would write your Writes[Creature] as following (using new Json syntax to re-show it even if it didn’t exist in Play2.0.x ;) ):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import play.api.libs.json._

implicit val creatureWrites = new Writes[Creature] {
  def writes(c: Creature): JsValue = {
    Json.obj(
      "name" -> c.name,
      "isDead" -> c.isDead,
      "weight" -> c.weight
    )
  }
}

scala> val gizmo = Creature("gremlins", false, 1.0F)
scala> val gizmojs = Json.toJson(gizmo)
gizmojs: play.api.libs.json.JsValue = {"name":"gremlins","isDead":false,"weight":1.0}

Writes in Play2.1.x

No suspense to be kept: in Play2.1, you write Writes exactly in the same way :D

So what’s the difference?
As presented in Part 1, Reads could be combined using simple logical operators.
Using functional Scala power, we were able to provide combinators for Writes[T].

If you want more theoretical aspects about the way it was implemented based on generic functional structures adapted to our needs, you can read this post “Applicatives are too restrictive, breaking Applicatives and introducing Functional Builders” written by @sadache

Writes main change: combinators

Once again, code first: re-writing previous Writes[T] using combinators.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// IMPORTANT import this to have the required tools in your scope
import play.api.libs.json._
// imports required functional generic structures
import play.api.libs.json.util._
// imports implicit structure for Writes only (always try to import only what you need)
import play.api.libs.json.Writes._

implicit val creatureWrites = (
  (__ \ "name").write[String] and
  (__ \ "isDead").write[Boolean] and
  (__ \ "weight").write[Float]
)(unlift(Creature.unapply))

// or using the operators inspired by Scala parser combinators for those who know them
implicit val creatureWrites = (
  (__ \ "name").write[String] ~
  (__ \ "isDead").write[Boolean] ~
  (__ \ "weight").write[Float]
)(unlift(Creature.unapply))

scala> val c = Creature("gremlins", false, 1.0F)
scala> val js = Json.toJson(c)
js: play.api.libs.json.JsValue = {"name":"gremlins","isDead":false,"weight":1.0}

It looks exactly like Reads[T] except a few things, isn’t it?
Let’s explain a bit (by copying Reads article changing just a few things… I’m lazy ;)):

import play.api.libs.json.Writes._

It imports only the required stuff for Writes[T] without interfering with other imports.


(__ \ "name").write[String]

You apply write[String] on this JsPath (exactly the same as Reads)


and is just an operator meaning Writes[A] and Writes[B] => Builder[Writes[A ~ B]]
  • A ~ B just means Combine A and B but it doesn’t suppose the way it is combined (can be a tuple, an object, whatever…)
  • Builder is not a real type but I introduce it just to tell that the operator and doesn’t create directly a Writes[A ~ B] but an intermediate structure that is able to build a Writes[A ~ B] or to combine with another Writes[C]

(…)(unlift(Creature.unapply)) builds a Writes[Creature]
  • (__ \ "name").write[String] and (__ \ "isDead").write[Boolean] and (__ \ "weight").write[Float] builds a Builder[Writes[String ~ Boolean ~ Float])] but you want a Writes[Creature].
  • So you apply the Builder[Writes[String ~ Boolean ~ String])] to a function Creature => (String, Boolean, Float) to finally obtain a Writes[Creature]. Please note that it may seem a bit strange to provide Creature => (String, Boolean, Float) to obtain a Writes[Creature] from a Builder[Writes[String ~ Boolean ~ String])] but it’s due to the contravariant nature of Writes[-T].
  • We have Creature.unapply but its signature is Creature => Option[(String, Boolean, Float)] so we unlift it to obtain Creature => (String, Boolean, Float).

The only thing you have to keep in mind is this unlift call which might not be natural at first sight!

As you can deduce by yourself, the Writes[T] is far easier than the Reads[T] case because when writing, it doesn’t try to validate so there is no error management at all.

Moreover, due to this, you have to keep in mind that operators provided for Writes[T] are not as rich as for Reads[T]. Do you remind keepAnd and andKeep operators? They don’t have any meaning for Writes[T]. When writing A~B, you write A and B but not only A or only B. So and is the only operators provided for Writes[T].

Complexifying the case

Let’s go back to our more complex sample used in end of Part1. Remember that we had imagined that our creature was modelled as following:

1
2
3
4
5
6
7
8
9
case class Creature(
  name: String,
  isDead: Boolean,
  weight: Float,
  email: String, // email format and minLength(5)
  favorites: (String, Int), // the stupid favorites
  friends: List[Creature] = Nil, // yes by default it has no friend
  social: Option[String] = None // by default, it's not social
)

Let’s write corresponding Writes[Creature]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// IMPORTANT import this to have the required tools in your scope
import play.api.libs.json._
// imports required functional generic structures
import play.api.libs.json.util._
// imports implicit structure for Writes only (always try to import only what you need)
import play.api.libs.json.Writes._

implicit val creatureWrites: Writes[Creature] = (
  (__ \ "name").write[String] and
  (__ \ "isDead").write[Boolean] and
  (__ \ "weight").write[Float] and
  (__ \ "email").write[String] and
  (__ \ "favorites").write(
      (__ \ "string").write[String] and
      (__ \ "number").write[Int]
      tupled
  ) and
  (__ \ "friends").lazyWrite(Writes.traversableWrites[Creature](creatureWrites)) and
  (__ \ "social").write[Option[String]]
)(unlift(Creature.unapply))

val gizmo = Creature("gremlins", false, 1.0F, "gizmo@midnight.com", ("alpha", 85), List(), Some("@gizmo"))
val gizmojs = Json.toJson(gizmo)
gizmojs: play.api.libs.json.JsValue = {"name":"gremlins","isDead":false,"weight":1.0,"email":"gizmo@midnight.com","favorites":{"string":"alpha","number":85},"friends":[],"social":"@gizmo"}

val zombie = Creature("zombie", true, 100.0F, "shaun@dead.com", ("ain", 2), List(gizmo), None)
val zombiejs = Json.toJson(zombie)
zombiejs: play.api.libs.json.JsValue = {"name":"zombie","isDead":true,"weight":100.0,"email":"shaun@dead.com","favorites":{"string":"ain","number":2},"friends":[{"name":"gremlins","isDead":false,"weight":1.0,"email":"gizmo@midnight.com","favorites":{"string":"alpha","number":85},"friends":[],"social":"@gizmo"}],"social":null

You can see that it’s quite straightforward. it’s far easier than Reads[T] as there are no special operator. Here are the few things to explain:

(__ \ "favorites").write(…)
(__ \ "string").write[String] and
(__ \ "number").write[Int]
tupled
  • Remember that (__ \ "string").write[String](…) and (__ \ "number").write[Int](…) => Builder[Writes[String ~ Int]]
  • What means tupled ? as for Reads[T], it “tuplizes” your Builder: Builder[Writes[A ~ B]].tupled => Writes[(A, B)]

(__ \ "friend").lazyWrite(Writes.traversableWrites[Creature](creatureWrites))

It’s the symmetric code for lazyRead to treat recursive field on Creature class itself:

  • Writes.traversableWrites[Creature](creatureWrites) creates a Writes[Traversable[Creature]] passing the Writes[Creature] itself for recursion (please note that a list[Creature]should appear very soon ;))
  • (__ \ "friends").lazyWrite[A](r: => Writes[A])) : lazyWrite expects a Writes[A] value passed by name to allow the type recursive construction. This is the only refinement that you must keep in mind in this very special recursive case.

FYI, you may wonder why Writes.traversableWrites[Creature]: Writes[Traversable[Creature]] can replace Writes[List[Creature]]?
This is because Writes[-T] is contravariant meaning: if you can write a Traversable[Creature], you can write a List[Creature] as List inherits Traversable (relation of inheritance is reverted by contravariance).

What about combinators for Format?

Remember in Play2.1, there was a feature called Format[T] extends Reads[T] with Writes[T].
It mixed Reads[T] and Writes[T] together to provide serialization/deserialization at the same place.

Play2.1 provide combinators for Reads[T] and Writes[T]. What about combinators for Format[T] ?

Let’s go back to our very simple sample:

1
2
3
4
5
case class Creature(
  name: String,
  isDead: Boolean,
  weight: Float
)

Here is how you write the Reads[Creature]:

1
2
3
4
5
6
7
8
import play.api.libs.json.util._
import play.api.libs.json.Reads._

val creatureReads = (
  (__ \ "name").read[String] and
  (__ \ "isDead").read[Boolean] and
  (__ \ "weight").read[Float]
)(Creature)

Please remark that I didn’t use implicit so that there is no implicit Reads[Creature] in the context when I’ll define Format[T]

Here is how you write the Writes[Creature]:

1
2
3
4
5
6
7
8
import play.api.libs.json.util._
import play.api.libs.json.Writes._

val creatureWrites = (
  (__ \ "name").write[String] and
  (__ \ "isDead").write[Boolean] and
  (__ \ "weight").write[Float]
)(unlift(Creature.unapply))

How to gather both Reads/Writes to create a Format[Creature]?

1st way = create from existing reads/writes

You can reuse existing Reads[T] and Writes[T] to create a Format[T] as following:

1
2
3
4
5
6
7
8
9
10
11
12
implicit val creatureFormat = Format(creatureReads, creatureWrites)

val gizmojs = Json.obj(
  "name" -> "gremlins",
  "isDead" -> false,
  "weight" -> 1.0F
)

val gizmo = Creature("gremlins", false, 1.0F)

assert(Json.fromJson[Creature](gizmojs).get == gizmo)
assert(Json.toJson(gizmo) == gizmojs)

2nd way = create using combinators

We have Reads and Writes combinators, isn’t it?
Play2.1 also provides Format Combinators due to the magic of functional programming (actually it’s not magic, it’s just pure functional programming;) )

As usual, code 1st:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import play.api.libs.json.util._
import play.api.libs.json.Format._

implicit val creatureFormat = (
  (__ \ "name").format[String] and
  (__ \ "isDead").format[Boolean] and
  (__ \ "weight").format[Float]
)(Creature.apply, unlift(Creature.unapply))

val gizmojs = Json.obj(
  "name" -> "gremlins",
  "isDead" -> false,
  "weight" -> 1.0F
)

val gizmo = Creature("gremlins", false, 1.0F)

assert(Json.fromJson[Creature](gizmojs).get == gizmo)
assert(Json.toJson(gizmo) == gizmojs)

Nothing too strange…

(__ \ "name").format[String]

It creates a format[String] reading/writing at the given JsPath


( )(Creature.apply, unlift(Creature.unapply))

To map to a Scala structure:

  • Reads[Creature] requires a function (String, Boolean, Float) => Creature
  • Writes[Creature] requires a function Creature => (String, Boolean, Float)

So as Format[Creature] extends Reads[Creature] with Writes[Creature] we provide Creature.apply and unlift(Creature.unapply) and that’s all folks…

More complex case

The previous sample is a bit dumb because the structure is really simple and because reading/writing is symmetric. We have:

1
Json.fromJson[Creature](Json.toJson(creature)) == creature

In this case, you read what you write and vis versa. So you can use the very simple JsPath.format[T] functions which build both Reads[T] and Writes[T] together.

But if we take our usual more complicated case class, how to write the Format[T]?

Remind the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import play.api.libs.json._
import play.api.libs.json.util._

// The case class
case class Creature(
  name: String,
  isDead: Boolean,
  weight: Float,
  email: String, // email format and minLength(5)
  favorites: (String, Int), // the stupid favorites
  friends: List[Creature] = Nil, // yes by default it has no friend
  social: Option[String] = None // by default, it's not social
)

import play.api.data.validation.ValidationError
import play.api.libs.json.Reads._

// defines a custom reads to be reused
// a reads that verifies your value is not equal to a give value
def notEqualReads[T](v: T)(implicit r: Reads[T]): Reads[T] = Reads.filterNot(ValidationError("validate.error.unexpected.value", v))( _ == v )

def skipReads(implicit r: Reads[String]): Reads[String] = r.map( _.substring(2) )

val creatureReads: Reads[Creature] = (
  (__ \ "name").read[String] and
  (__ \ "isDead").read[Boolean] and
  (__ \ "weight").read[Float] and
  (__ \ "email").read(email keepAnd minLength[String](5)) and
  (__ \ "favorites").read(
      (__ \ "string").read[String]( notEqualReads("ni") andKeep skipReads ) and
      (__ \ "number").read[Int]( max(86) or min(875) )
      tupled
  ) and
  (__ \ "friends").lazyRead( list[Creature](creatureReads) ) and
  (__ \ "social").read(optional[String])
)(Creature)

import play.api.libs.json.Writes._

val creatureWrites: Writes[Creature] = (
  (__ \ "name").write[String] and
  (__ \ "isDead").write[Boolean] and
  (__ \ "weight").write[Float] and
  (__ \ "email").write[String] and
  (__ \ "favorites").write(
      (__ \ "string").write[String] and
      (__ \ "number").write[Int]
      tupled
  ) and
  (__ \ "friends").lazyWrite(Writes.traversableWrites[Creature](creatureWrites)) and
  (__ \ "social").write[Option[String]]
)(unlift(Creature.unapply))

As you can see, creatureReads and creatureWrites are not exactly symmetric and couldn’t be merged in one single Format[Creature] as done previously.

1
Json.fromJson[Creature](Json.toJson(creature)) != creature

Hopefully, as done previously, we can build a Format[T] from a Reads[T] and a Writes[T].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
implicit val creatureFormat: Format[Creature] = Format(creatureReads, creatureWrites)

// Testing Serialization of Creature to Json
val gizmo = Creature("gremlins", false, 1.0F, "gizmo@midnight.com", ("alpha", 85), List(), Some("@gizmo"))
val zombie = Creature("zombie", true, 100.0F, "shaun@dead.com", ("ain", 2), List(gizmo), None)

val zombiejs = Json.obj(
  "name" -> "zombie",
  "isDead" -> true,
  "weight" -> 100.0,
  "email" -> "shaun@dead.com",
  "favorites" -> Json.obj(
      "string" -> "ain",
      "number" -> 2
  ),
  "friends" -> Json.arr(
      Json.obj(
          "name" -> "gremlins",
          "isDead" -> false,
          "weight" -> 1.0,
          "email" -> "gizmo@midnight.com",
          "favorites" -> Json.obj(
              "string" -> "alpha",
              "number" -> 85
          ),
          "friends" -> Json.arr(),
          "social" -> "@gizmo"
      )
  ),
  "social" -> JsNull
)

assert(Json.toJson(zombie) == zombiejs)

// Testing Deserialization of JSON to Creature (note the dissymetric reading)
val gizmo2 = Creature("gremlins", false, 1.0F, "gizmo@midnight.com", ("pha", 85), List(), Some("@gizmo"))
val zombie2 = Creature("zombie", true, 100.0F, "shaun@dead.com", ("n", 2), List(gizmo2), None)

assert(Json.fromJson[Creature](zombiejs).get == zombie2)


Conclusion & much more…

So here is the end of this 2nd part.

Json combinator is cool!
Now what about transforming Json into Json???
Why would you need this?
Hmmm: why not receive JSON, validate/transform it, send it to a managing Json (Mongo for ex or others), read it again from the DB, modify it a bit and send it out…
Json “coast to coast” without any model class…

Let’s tease a bit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
val jsonTransform = (
  (__ \ "key1").json.pickBranch and
  (__ \ "key2").json.pickBranch(
    (__ \ "key22").json.put( (__ \ "key22").json.pick.map( js => js \ "key221" ) ) and
    (__ \ "key23").json.put( (__ \ "key23").json.pick.map{ case JsString(s) => JsString(s + "123") } )
    reduce
  )
) reduce

val js = Json.obj(
  "key1" -> "alpha",
  "key2" -> Json.obj("key22" -> Json.obj("key221" -> "beta"), "key23" -> "gamma"),
)

assert(js.validate(jsonTransform), JsSuccess( Json.obj("key1" -> "alpha", "key2" -> Json.obj( "key22" -> "beta", "key23" -> "gamma123" ) ) ) )

Next parts about Json generators/transformers ;)

Have fun…

Addendum: recent API refactoring (modified in the articled)

  • Reads[A] provided Reads[B] has been renamed to Reads[A] keepAnd Reads[B]
  • Reads[A] andThen Reads[B] has been renamed to Reads[A] andKeep Reads[B]

In incoming Play2.1 version, a huge re-thinking has been done about JSON API provided by Play2.0.x which provides some great features but is clearly just the tip of the iceberg…
Here is a first presentation of those evolutions aimed at unleashing your JSON usage in Play2 and revealing new forms of manipulation of web dataflows from/to external data systems.
A usecase of this is manipulating DB structures directly using Json without any class models for document oriented structures such as MongoDB

BTW Don’t forget the recent release of new MongoDB async/non-blocking driver ReactiveMongo ;-)

Summary of main new features added in Play2.1

  • Simplified Json Objects/Arrays syntax
    1
    2
    3
    4
    5
    
    Json.obj(
      "key" -> "value",
      "key2" -> 123,
      "key3" -> Json.arr("alpha", 143.55, false)
    )
    
  • JsPath for manipulating JSON in XmlPath-style
    1
    
    (JsPath \ "key" \ "key2" \\ "key3")(3)
    
  • Reads[T] / Writes[T] / Format[T] combinators based on JsPath and simple logic operators
    1
    2
    3
    4
    5
    
    val customReads: Reads[(String, Float, List[String])] =
      (JsPath \ "key1").read[String](email keepAnd minLength(5)) and
      (JsPath \ "key2").read[Float](min(45)) and
      (JsPath \ "key3").read[List[String]]
      tupled
    
  • Reads[T] API now validates JSON by returning a monadic JsResult[T] being a JsSuccess[T] or a JsError aggregating all validation errors
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    val js = Json.obj(
      "key1" -> "alpha",
      "key2" -> 123.345F,
      "key3" -> Json.arr("alpha", "beta")
    )
    
    scala> customReads.reads(js)
    res5: JsSuccess(("alpha", 123.345F, List("alpha", "beta")))
    
    customReads.reads(js).fold(
      valid = { res =>
        val (s, f, l): (String, Float, List[String]) = res
        ...
      },
      invalid = { errors => ... }
    )
    

Now let’s go in the details ;)



Very Quick Json syntax

Concerning the new Json syntax, I won’t spend time on this, it’s quite explicit and you can try it very easily by yourself.

1
2
3
4
5
6
7
8
9
val js = Json.obj(
  "key1" -> "value1",
  "key2" -> 234,
  "key3" -> Json.obj(
    "key31" -> true,
    "key32" -> Json.arr("alpha", "beta", 234.13),
    "key33" -> Json.obj("key1" -> "value2", "key34" -> "value34")
  )
)


Quick JsPath

You certainly know XMLPath in which you can access a node of an XML AST using a simple syntax based on path.
JSON is already an AST and we can apply the same kind of syntax to it and logically we called it JsPath.

All following examples use JSON defined in previous paragraph.

Building JsPath

1
2
3
4
5
6
7
8
9
10
11
// Simple path
JsPath \ "key1"

// 2-levels path
JsPath \ "key3" \ "key33"

// indexed path
(JsPath \ "key3" \ "key32")(2) // 2nd element in a JsArray

// multiple paths
JsPath \\ "key1"

Alternative syntax

JsPath is quite cool but we found this syntax could be made even clearer to highlight Reads[T] combinators in the code.
That’s why we provide an alias for JsPath: __ (2 underscores).
You can use it or not. This is just a visual facility because with it, you immediately find your JsPath in the code…

You can write:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Simple path
__ \ "key1"

// 2-levels path
__ \ "key3" \ "key33"

// indexed path
(__ \ "key3" \ "key32")(2) // 2nd element in a JsArray

// multiple paths
__ \\ "key1"

// a sample on Reads[T] combinators to show the difference with both syntax
// DON'T TRY TO UNDERSTAND THIS CODE RIGHT NOW… It's explained in next paragraphs
val customReads =
  (JsPath \ "key1").read(
    (JsPath \ "key11").read[String] and
    (JsPath \ "key11").read[String] and
    (JsPath \ "key11").read[String]
    tupled
  ) and
  (JsPath \ "key2").read[Float](min(45)) and
  (JsPath \ "key3").read(
    (JsPath \ "key31").read[String] and
    (JsPath \ "key32").read[String] and
    (JsPath \ "key33").read[String]
    tupled
  )
  tupled
  
// with __
val customReads =
  (__ \ "key1").read(
    (__ \ "key11").read[String] and
    (__ \ "key11").read[String] and
    (__ \ "key11").read[String]
    tupled
  ) and
  (__ \ "key2").read[Float](min(45)) and
  (__ \ "key3").read[List[String]] (
    (__ \ "key31").read[String] and
    (__ \ "key32").read[String] and
    (__ \ "key33").read[String]
    tupled
  )
  tupled
  
// You can immediately see the structure of the JSON tree

Accessing value of JsPath

The important function to retrieve the value at a given JsPath in a JsValue is the following:

1
2
3
4
sealed trait PathNode {
  def apply(json: JsValue): List[JsValue]
  
}

As you can see, this function retrieves a List[JsValue]

You can simply use it like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// build a JsPath
scala> (__ \ "key1")(js)
res12: List[play.api.libs.json.JsValue] = List("value1")  // actually this is JsString("value1")

// 2-levels path
scala> (__ \ "key3" \ "key33")(js)
res13: List[play.api.libs.json.JsValue] = List({"key":"value2","key34":"value34"})

// indexed path
scala> (__ \ "key3" \ "key32")(2)(js)
res14: List[play.api.libs.json.JsValue] = List(234.13)

// multiple paths
scala> (__ \\ "key1")(js)
res17: List[play.api.libs.json.JsValue] = List("value1", "value2")


Reads[T] is now a validator

Reads in Play2.0.x

Do you remember how you had to write a Json Reads[T] in Play2.0.x ?
You had to override the reads function.

1
2
3
4
5
6
7
trait Reads[A] {
  self =>
  /**
   * Convert the JsValue into a A
   */
  def reads(json: JsValue): A
}

Take the following simple case class that you want to map on JSON structure:

1
2
3
4
5
case class Creature(
  name: String,
  isDead: Boolean,
  weight: Float
)

In Play2.0.x, you would write your reader as following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import play.api.libs.json._

implicit val creatureReads = new Reads[Creature] {
  def reads(js: JsValue): Creature = {
    Creature(
      (js \ "name").as[String],
      (js \ "isDead").as[Boolean],
      (js \ "weight").as[Float]
    )
  }
}

scala> val js = Json.obj( "name" -> "gremlins", "isDead" -> false, "weight" -> 1.0F)
scala> val c = js.as[Creature]
c: Creature("gremlins", false, 1.0F)

Easy isn’t it ? So what’s the problem if it’s so easy?

Imagine, you pass the following JSON with a missing field:

1
val js = Json.obj( "name" -> "gremlins", "weight" -> 1.0F)

What happens?

1
2
3
4
5
java.lang.RuntimeException: Boolean expected
  at play.api.libs.json.DefaultReads$BooleanReads$.reads(Reads.scala:98)
  at play.api.libs.json.DefaultReads$BooleanReads$.reads(Reads.scala:95)
  at play.api.libs.json.JsValue$class.as(JsValue.scala:56)
  at play.api.libs.json.JsUndefined.as(JsValue.scala:70)

WHATTTTTTT???? Yes ugly RuntimeException (not even subtyped) but you can work around it using JsValue.asOpt[T] :)

1
2
scala> val c: Option[Creature] = js.asOpt[Creature]
c: None

Cool but you only know that the deserialization Json => Creature failed but not where or on which field(s)?



Reads in Play2.1

We couldn’t keep this imperfect API as is and in Play2.1, the Reads[T] API has changed into :

1
2
3
4
5
6
7
trait Reads[A] {
  self =>
  /**
   * Convert the JsValue into a A
   */
  def reads(json: JsValue): JsResult[A]
}

Yes you have to refactor all your existing custom Reads but you’ll see you’ll get lots of new interesting features…

So you remark immediately JsResult[A] which is a very simple structure looking a bit like an Either applied to our specific problem.

JsResult[A] can be of 2 types:

  • JsSuccess[A] when readssucceeds
1
2
3
4
5
6
7
case class JsSuccess[A](
  value: T, // the value retrieved when deserialization JsValue => A worked
  path: JsPath = JsPath() // the root JsPath where this A was read in the JsValue (by default, it's the root of the JsValue)
) extends JsResult[T]

// To create a JsSuccess from a value, simply do:
val success = JsSuccess(Creature("gremlins", false, 1.0))
  • JsError[A] when reads fails

Please note the greatest advantage of JsError is that it’s a cumulative error which can store several errors discovered in the Json at different JsPath

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
case class JsError(
  errors: Seq[(JsPath, Seq[ValidationError])]
  // the errors is a sequence of JsPath locating the path 
  // where there was an error in the JsValue and validation 
  // errors for this path
) extends JsResult[Nothing]

// ValidationError is a simple message with arguments (which can be mapped on localized messages)
case class ValidationError(message: String, args: Any*)

// To create a JsError, there are a few helpers and for ex:
val errors1 = JsError( __ \ 'isDead, ValidationError("validate.error.missing", "isDead") )
val errors2 = JsError( __ \ 'name, ValidationError("validate.error.missing", "name") )

// Errors are cumulative which is really interesting
scala> val errors = errors1 ++ errors2
errors: JsError(List((/isDead,List(ValidationError(validate.error.missing,WrappedArray(isDead)))), (/name,List(ValidationError(validate.error.missing,WrappedArray(name))))))

So what’s interesting there is that JsResult[A] is a monadic structure and can be used with classic functions of such structures:

  • flatMap[X](f: A => JsResult[X]): JsResult[X]
  • fold[X](invalid: Seq[(JsPath, Seq[ValidationError])] => X, valid: A => X)
  • map[X](f: A => X): JsResult[X]
  • filter(p: A => Boolean)
  • collect[B](otherwise:ValidationError)(p:PartialFunction[A,B]): JsResult[B]
  • get: A

And some sugar such :

  • asOpt
  • asEither

Reads[A] has become a validator

As you may understand, using the new Reads[A], you don’t only deserialize a JsValue into another structure but you really validate the JsValue and retrieve all the validation errors.
BTW, in JsValue, a new function called validate has appeared:

1
2
3
4
5
6
7
8
9
10
11
12
13
trait JsValue {

  def validate[T](implicit _reads: Reads[T]): JsResult[T] = _reads.reads(this)

  // same behavior but it throws a specific RuntimeException JsResultException now
  def as[T](implicit fjs: Reads[T]): T
  // exactly the same behavior has before
  def asOpt[T](implicit fjs: Reads[T]): Option[T]

}

// You can now write if you got the right implicit in your scope
val res: JsResult[Creature] = js.validate[Creature])

Manipulating a JsResult[A]

So when manipulating a JsResult, you don’t access the value directly and it’s preferable to use map/flatmap/fold to modify the value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
val res: JsResult[Creature] = js.validate[Creature]

// managing the success/error and potentially return something
res.fold(
  valid = { c => println( c ); c.name },
  invalid = { e => println( e ); e }
)

// getting the name directly (using the get can throw a NoSuchElementException if it's a JsError)
val name: JsSuccess[String] = res.map( creature => creature.name ).get

// filtering the result
val name: JsSuccess[String] = res.filter( creature => creature.name == "gremlins" ).get

// a classic Play action
def getNameOnly = Action(parse.json) { request =>
  val json = request.body
  json.validate[Creature].fold(
    valid = ( res => Ok(res.name) ),
    invalid = ( e => BadRequest(e.toString) )
  )
}

Rewriting the Reads[T] with JsResult[A]

The Reads[A] API returning a JsResult, you can’t write your Reads[A] as before as you must return a JsResult gathering all found errors.
You could imagine simply compose Reads[T] with flatMap :

1
2
3
4
5
6
7
8
9
10
11
12
// DO NOT USE, WRONG CODE
implicit val creatureReads = new Reads[Creature] {
  def reads(js: JsValue): JsResult[Creature] = {
    (js \ "name").validate[String].flatMap{ name =>
      (js \ "isDead").validate[Boolean].flatMap { isDead =>
      (js \ "weight").validate[Float].map { weight =>
        Creature(name, isDead, weight)
      }
    }
  }
  }
}

Remember the main purpose of JsResult is to gather all found errors while validating the JsValue.

JsResult.flatMap is pure monadic function (if you don’t know what it is, don’t care about it, you can understand without it) implying that the function that you pass to flatMap() is called only if the result is a JsSuccess else it just returns the JsError.
This means the previous code won’t aggregate all errors found during validation and will stop at first error which is exactly what we don’t want.

Actually, Monad pattern is not good in our case because we are not just composing Reads but we expect combining them following the schema:

1
2
3
Reads[String] AND Reads[Boolean] AND Reads[Float]
  => Reads[(String, Boolean, Float)]
     => Reads[Creature]

So we need something else to be able to combine our Reads and this is the greatest new feature that Play2.1 brings for JSON :
THE READS combinators with JsPath


If you want more theoretical aspects about the way it was implemented based on generic functional structures adapted to our needs, you can read this post “Applicatives are too restrictive, breaking Applicatives and introducing Functional Builders” written by @sadache

Rewriting the Reads[T] with combinators

Go directly to the example as practice is often the best :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// IMPORTANT import this to have the required tools in your scope
import play.api.libs.json.util._

implicit val creatureReads = (
  (__ \ "name").read[String] and
  (__ \ "isDead").read[Boolean] and
  (__ \ "weight").read[Float]
)(Creature.apply _)

// or in a simpler way as case class has a companion object with an apply function
implicit val creatureReads = (
  (__ \ "name").read[String] and
  (__ \ "isDead").read[Boolean] and
  (__ \ "weight").read[Float]
)(Creature)

// or using the operators inspired by Scala parser combinators for those who know them
implicit val creatureReads = (
  (__ \ "name").read[String] ~
  (__ \ "isDead").read[Boolean] ~
  (__ \ "weight").read[Float]
)(Creature)

So there is nothing quite complicated, isn’t it?

(__ \ "name") is the JsPath where you gonna apply read[String]

and is just an operator meaning Reads[A] and Reads[B] => Builder[Reads[A ~ B]]
  • A ~ B just means Combine A and B but it doesn’t suppose the way it is combined (can be a tuple, an object, whatever…)
  • Builder is not a real type but I introduce it just to tell that the operator and doesn’t create directly a Reads[A ~ B] but an intermediate structure that is able to build a Reads[A ~ B] or to combine with another Reads[C]

(…)(Creature) builds a Reads[Creature]
  • (__ \ "name").read[String] and (__ \ "isDead").read[Boolean] and (__ \ "weight").read[Float] builds a Builder[Reads[String ~ Boolean ~ Float])] but you want a Reads[Creature].
  • So you apply the Builder[Reads[String ~ Boolean ~ String])] to the function Creature.apply = (String, Boolean, Float) => Creature constructor to finally obtain a Reads[Creature]

Try it:

1
2
3
scala> val js = Json.obj( "name" -> "gremlins", "isDead" -> false, "weight" -> 1.0F)
scala> js.validate[Creature]
res1: play.api.libs.json.JsResult[Creature] = JsSuccess(Creature(gremlins,false,1.0),) // nothing after last comma because the JsPath is ROOT by default

Now what happens if you have an error now?

1
2
3
scala> val js = Json.obj( "name" -> "gremlins", "weight" -> 1.0F)
scala> js.validate[Creature]
res2: play.api.libs.json.JsResult[Creature] = JsError(List((/isDead,List(ValidationError(validate.error.missing-path,WrappedArray())))))

Explicit, isn’t it?

Complexifying the case

Ok, I see what you think : what about more complex cases where you have several constraints on a field and embedded Json in Json and recursive classes and whatever…

Let’s imagine our creature:

  • is a relatively modern creature having an email and hating email addresses having less than 5 characters for a reason only known by the creature itself.
  • may have 2 favorites data:
    • 1 String (called “string” in JSON) which shall not be “ni” (because it loves Monty Python too much to accept this) and then to skip the first 2 chars
    • 1 Int (called “number” in JSON) which can be less than 86 or more than 875 (don’t ask why, this is creature with a different logic than ours)
  • may have friend creatures
  • may have an optional social account because many creatures are not very social so this is quite mandatory

Now the class looks like:

1
2
3
4
5
6
7
8
9
case class Creature(
  name: String,
  isDead: Boolean,
  weight: Float,
  email: String, // email format and minLength(5)
  favorites: (String, Int), // the stupid favorites
  friends: List[Creature] = Nil, // yes by default it has no friend
  social: Option[String] = None // by default, it's not social
)

Play2.1 provide lots of generic Reads helpers:

  • JsPath.read[A](implicit reads:Reads[A]) can be passed a custom Reads[A] which is applied to the JSON content at this JsPath. So with this property, you can compose hierarchically Reads[T] which corresponds to JSON tree structure.
  • JsPath.readOpt allows Reads[Option[T]]
  • Reads.email which validates the String has email format
  • Reads.minLength(nb) validates the minimum length of a String
  • Reads[A] or Reads[A] => Reads[A] operator is a classic OR logic operator
  • Reads[A] keepAnd Reads[B] => Reads[A] is an operator that tries Reads[A] and Reads[B] but only keeps the result of Reads[A] (For those who know Scala parser combinators keepAnd == <~ )
  • Reads[A] andKeep Reads[B] => Reads[B] is an operator that tries Reads[A] and Reads[B] but only keeps the result of Reads[B] (For those who know Scala parser combinators andKeep == ~> )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// import just Reads helpers in scope
import play.api.libs.json._
import play.api.libs.json.util._
import play.api.libs.json.Reads._
import play.api.data.validation.ValidationError

// defines a custom reads to be reused
// a reads that verifies your value is not equal to a give value
def notEqualReads[T](v: T)(implicit r: Reads[T]): Reads[T] = Reads.filterNot(ValidationError("validate.error.unexpected.value", v))( _ == v )

def skipReads(implicit r: Reads[String]): Reads[String] = r.map( _.substring(2) )

implicit val creatureReads: Reads[Creature] = (
  (__ \ "name").read[String] and
  (__ \ "isDead").read[Boolean] and
  (__ \ "weight").read[Float] and
  (__ \ "email").read(email keepAnd minLength[String](5)) and
  (__ \ "favorites").read(
      (__ \ "string").read[String]( notEqualReads("ni") andKeep skipReads ) and
      (__ \ "number").read[Int]( max(86) or min(875) )
      tupled
  ) and
  (__ \ "friends").lazyRead( list[Creature](creatureReads) ) and
  (__ \ "social").readOpt[String]
)(Creature)

Many things above can be understood very logically but let’s explain a bit:

(__ \ "email").read(email keepAnd minLength[String](5))
  • As explained previously, (__ \ "email").read(…) applies the Reads[T] passed in parameter to function read at the given JsPath (__ \ "email")
  • email keepAnd minLength[String](5) => Reads[String] is a Js validator that verifies JsValue:
    1. is a String : email: Reads[String] so no need to specify type here
    2. has email format
    3. has min length of 5 (we precise the type here because minLength is a generic Reads[T])
  • Why not email and minLength[String](5)? because, as explained previously, it would generate a Builder[Reads[(String, String)]] whereas you expect a Reads[String]. The keepAnd operator (aka <~) does what we expect: it validates both sides but if succeeded, it keeps only the result on left side.

notEqualReads("ni") andKeep skipReads
  • No need to write notEqualReads[String]("ni") because String type is inferred from (__ \ "knight").read[String] (the power of Scala typing engine)
  • skipReads is a customReads that skips the first 2 chars
  • andKeep operator (aka ~>) is simple to undestand : it validates the left and right side and if both succeeds, only keeps the result on right side. In our case, only the result of skipReads is kept and not the result of notEqualReads.

max(86) or min(875)
  • Nothing to explain there, isn’t it ? or is the classic ORlogic operator, nothing else

(__ \ "favorites").read(…)
(__ \ "string").read[String]( notEqualReads("ni") andKeep notEqualReads("swallow") ) and
(__ \ "number").read[Int]( max(86) or min(875) )
tupled
  • Remember that (__ \ "string").read[String](…) and (__ \ "number").read[Int](…) => Builder[Reads[(String, Int)]]
  • What means tupled ? Builder[Reads[(String, Int)]] can be used with a case class apply function to build the Reads[Creature] for ex. But it provides also tupled which is quite easy to understand : it “tuplizes” your Builder: Builder[Reads[(A, B)]].tupled => Reads[(A, B)]
  • Finally (__ \ "favorites").read(Reads[(String, Int)] will validate a (String, Int) which is the expected type for field favorites

(__ \ "friend").lazyRead( list[Creature](creatureReads) )

This is the most complicated line in this code. But you can understand why: the friend field is recursive on the Creature class itself so it requires a special treatment.

  • list[Creature](…) creates a Reads[List[Creature]]
  • list[Creature](creatureReads) passes explicitly creatureReads as an argument because it’s recursive and Scala requires that to resolve it. Nothing too complicated…
  • (__ \ "friend").lazyRead[A](r: => Reads[A])) : lazyRead expects a Reads[A] value passed by name to allow the type recursive construction. This is the only refinement that you must keep in mind in this very special recursive case.

(__ \ "social").readOpt[String]

Nothing quite complicated to understand: we need to read an option and readOpt helps in doing this.

Now we can use this Reads[Creature]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
val gizmojs = Json.obj(
  "name" -> "gremlins",
  "isDead" -> false,
  "weight" -> 1.0F,
  "email" -> "gizmo@midnight.com",
  "favorites" -> Json.obj("string" -> "alpha", "number" -> 85),
  "friends" -> Json.arr(),
  "social" -> "@gizmo"
)

scala> val gizmo = gizmojs.validate[Creature]
gizmo: play.api.libs.json.JsResult[Creature] = JsSuccess(Creature(gremlins,false,1.0,gizmo@midnight.com,(pha,85),List(),Some(@gizmo)),)

val shaunjs = Json.obj(
  "name" -> "zombie",
  "isDead" -> true,
  "weight" -> 100.0F,
  "email" -> "shaun@dead.com",
  "favorites" -> Json.obj("string" -> "brain", "number" -> 2),
  "friends" -> Json.arr( gizmojs))

scala> val shaun = shaunjs.validate[Creature]
shaun: play.api.libs.json.JsResult[Creature] = JsSuccess(Creature(zombie,true,100.0,shaun@dead.com,(ain,2),List(Creature(gremlins,false,1.0,gizmo@midnight.com,(alpha,85),List(),Some(@gizmo))),None),)

val errorjs = Json.obj(
  "name" -> "gremlins",
  "isDead" -> false,
  "weight" -> 1.0F,
  "email" -> "rrhh",
  "favorites" -> Json.obj("string" -> "ni", "number" -> 500),
  "friends" -> Json.arr()
)

scala> errorjs.validate[Creature]
res0: play.api.libs.json.JsResult[Creature] = JsError(List((/favorites/string,List(ValidationError(validate.error.unexpected.value,WrappedArray(ni)))), (/email,List(ValidationError(validate.error.email,WrappedArray()), ValidationError(validate.error.minlength,WrappedArray(5)))), (/favorites/number,List(ValidationError(validate.error.max,WrappedArray(86)), ValidationError(validate.error.min,WrappedArray(875))))))


Conclusion & much more…

So here is the end of this 1st part not to make a too long article. But there are so many other features to explain and demonstrate and there will other parts very soon!!!

Reads[T] combinators are cool but you know what? Writes[T] & Format[T] can be combined too!

Let’s tease a bit:

1
2
3
4
5
implicit val creatureWrites = (
  (__ \ "name").write[String] and
  (__ \ "isDead").write[Boolean] and
  (__ \ "weight").write[Float]
)(Creature)

Next parts about Writes[T] combinators and another intriguing feature that I’ll name Json Generators ;)

Have fun…

Thanks to @loic_d, we have a French translation of this article there

You may have remarked that Play2 provides an intriguing feature called Iteratee (and its counterparts Enumerator and Enumeratee).

The main aim of this article is (to try) to make the Iteratee concept understandable for most of us with reasonably simple arguments and without functional/math theory.


This article is not meant to explain everything about Iteratee / Enumerator / Enumeratee but just the ideas behind it.
I’ll try to write another article to show practical samples of coding with Iteratee/Enumerator/Enumeratee.

Introduction

In Play2 doc, Iteratees are presented as a great tool to handle data streams reactively in a non-blocking, generic & composable way for modern web programming in distributed environments.

Seems great, isn’t it?
But what is an Iteratee exactly?
What is the difference between the Iteratee and the classic Iterator you certainly know?
Why use it? In which cases?
A bit obscure and complex, isn’t it?

If you are lazy and want to know just a few things

  • Iteratee is an abstraction of iteration over chunks of data in a non-blocking and asynchronous way
  • Iteratee is able to consume chunks of data of a given type from a producer generating data chunks of the same type called Enumerator
  • Iteratee can compute a progressive result from data chunks over steps of iteration (an incremented total for ex)
  • Iteratee is a thread-safe and immutable object that can be re-used over several `Enumerators`

1st advice: DO NOT SEARCH ABOUT ITERATEES ON GOOGLE

When you search on Google for Iteratee, you find very obscure explanations based on pure functional approach or even mathematical theories. Even the documentation on Play Framework (there) explains Iteratee with a fairly low-level approach which might be hard for beginners…

As a beginner in Play2, it might seem a bit tough to handle Iteratee concept presented in a really abstract way of manipulating data chunks.
It might seem so complicated that you will occult it and won’t use it.
It would be a shame because Iteratees are so powerful and provide a really interesting and new way to manipulate your data flows in a web app.

So, let’s try to explain things in a simple way. I don’t pretend to be a theoretical expert on those functional concepts and I may even say wrong things but I want to write an article that reflects what Iteratee means for me. Hope this could be useful to somebody…

This article uses Scala for code samples but the code should be understandable by anyone having a few notions of coding and I promise not to use any weird operator (but in last paragraph) ><> ><> ><> ><>

The code samples are based on incoming Play2.1 master code which greatly simplifies and rationalizes the code of Iteratee. So don’t be surprised if API doesn’t look like Play2.0.x sometimes

Reminders about iteration

Before diving into deep Iteratee sea, I want to clarify what I call iteration and to try to go progressively from the concept of Iterator to Iteratee.

You may know the Iterator concept you can find in Java. An Iterator allows to run over a collection of elements and then do something at each step of iteration. Let’s begin with a very simple iteration in Java classic way that sums all the integers of a List[Int]


The first very naive implementation with Java-like Iterator

1
2
3
4
5
6
7
8
9
10
val l = List(1, 234, 455, 987)

var total = 0 // will contain the final total
var it = l.iterator
while( it.hasNext ) {
  total += it.next
}

total
=> resXXX : Int = 1677

Without any surprise, iterating over a collection means :

  • Get an iterator from the collection,
  • Get an element from the iterator (if there are any),
  • Do something : here add the element value to the total,
  • If there are other elements, go to the next element,
  • Do it again,
  • Etc… till there are no more element to consume in the iterator
While iterating over a collection, we manipulate:
  • A state of iteration (is iteration finished ? This is naturally linked to the fact that there are more elements or not in the iterator?)
  • A context updated from one step to the next (the total)
  • An action updating the context

Rewrite that using Scala for-comprehension

1
for( item <- l ) { total += item }

It’s a bit better because you don’t have to use the iterator.

Rewrite it in a more functional way

1
l.foreach{ item => total += item }

Here we introduce List.foreach function accepting an anonymous function (Int => Unit) as a parameter and iterating over the list: for each element in the list, it calls the function which can update the context (here the total).

The anonymous function contains the action executed at each loop while iterating over the collection.

Rewrite in a more generic way

The anonymous function could be stored in a variable so that it can be reused in different places.

1
2
3
4
5
6
7
8
val l = List(1, 234, 455, 987)
val l2 = List(134, 664, 987, 456)
var total = 0
def step(item: Int) = total += item
l foreach step

total = 0
l2 foreach step

You should then say to me: “This is ugly design, your function has side-effects and uses a variable which is not a nice design at all and you even have to reset total to 0 at second call!”

That’s completely true:

Side-effect functions are quite dangerous because they change the state of something that is external to the function. This state is not exclusive to the function and can be changed by other entities, potentially in other threads. Function with side-effects are not recommended to have clean and robust designs and functional languages such as Scala tend to reduce side-effects functions to the strict necessary (IO operations for ex).

Mutable variables are also risky because if your code is run over several threads, if 2 threads try to change the value of the variable, who wins? In this case, you need synchronization which means blocking threads while writing the variable which means breaking one of the reason of being of Play2 (non-blocking web apps)…

Rewrite the code in an immutable way without side-effects

1
2
3
4
5
6
7
8
9
10
11
12
13
def foreach(l: List[Int]) = {
  def step(l: List[Int], total: Int): Int = {
    l match {
      case List() => total
      case List(elt) => total + elt
      case head :: tail => step(tail, total + head)
    }
  }

  step(l, 0)
}

foreach(l)

A bit more code, isn’t it ?

But please notice at least:

  • var total disappeared.
  • step function is the action executed at each step of iteration but it does something more than before: step also manages the state of the iteration. It executes as following:
    • If the list is empty, return current total
    • If the list has 1 element, return total + elt
    • If the list has more than 1 element, calls step with the tail elements and the new total total + head

So at each step of iteration, depending on the result of previous iteration, step can choose between 2 states:

  • Continue iteration because it has more elements
  • Stop iteration because it reached end of list or no element at all

Notice also that :

  • step is a tail-recursive function (doesn’t unfold the full call stack at the end of recursion and returns immediately) preventing from stack overflow and behaving almost like the previous code with Iterator
  • step transmits the remaining elements of the list & the new total to the next step
  • step returns the total without any side-effects at all

So, yes, this code consumes a bit more memory because it re-copies some parts of the list at each step (only the references to the elements) but it has no side-effect and uses only immutable data structures. This makes it very robust and distributable without any problem.

Notice you can write the code in a very shorter way using the wonderful functions provided by Scala collections:

1
l.foldLeft(0){ (total, elt) => total + elt }

Milestone


In this article, I consider iteration based on immutable structures propagated over steps. From this point of view, iterating involves:
  • receiving information from the previous step: context & state
  • getting current/remaining element(s)
  • computing a new state & context from remaining elements
  • propagating the new state & context to next step

Step by Step to Iterator & Iteratees

Now that we are clear about iteration, let’s go back to our Iteratee!!!

Imagine you want to generalize the previous iteration mechanism and be able to write something like:

1
2
3
4
5
6
def sumElements(...) = ...
def prodElements(...) = ...
def printElements(...) = ...
l.iterate(sumElements)
l.iterate(prodElements)
l.iterate(printElements)

Yes I know, with Scala collection APIs, you can do many things :)

Imagine you want to compose a first iteration with another one:

1
2
3
def groupElements(...) = ...
def printElements(...) = ...
l.iterate(groupElements).iterate(printElements)

Imagine you want to apply this iteration on something else than a collection:

  • a stream of data produced progressively by a file, a network connection, a database connection,
  • a data flow generated by an algorithm,
  • a data flow from an asynchronous data producer such as a scheduler or an actor.

Iteratees are exactly meant for this…

Just to tease, here is how you would write the previous sum iteration with an Iteratee.

1
2
val enumerator = Enumerator(1, 234, 455, 987)
enumerator.run(Iteratee.fold(0){ (total, elt) => total + elt }

Ok, it looks like the previous code and doesn’t seem to do much more…
Not false but trust me, it can do much more.
At least, it doesn’t seem so complicated?

But, as you can see, Iteratee is used with Enumerator and both concepts are tightly related.

Now let’s dive into those concepts on a step by step approach.


><> About Enumerator ><>

Enumerator is a more generic concept than collections or arrays

Till now, we have used collections in our iterations. But as explained before, we could iterate over something more generic, simply being able to produce simple chunks of data available immediately or asynchronously in the future.

Enumerator is designed for this purpose.

A few examples of simple Enumerators:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// an enumerator of Strings
val stringEnumerator: Enumerator[String] = Enumerate("alpha", "beta", "gamma")
// an enumerator of Integers
val integerEnumerator: Enumerator[Int] = Enumerate(123, 456, 789)
// an enumerator of Doubles
val doubleEnumerator: Enumerator[Double] = Enumerate(123.345, 456.543, 789.123)

// an Enumerator from a file
val fileEnumerator: Enumerator[Array[Byte]] = Enumerator.fromFile("myfile.txt")

// an Enumerator generated by a callback
// it generates a string containing current time every 500 milliseconds
// notice (and forget for the time being) the Promise.timeout which allows non-blocking mechanism
val dateGenerator: Enumerator[String] = Enumerator.generateM(
  play.api.libs.concurrent.Promise.timeout(
    Some("current time %s".format((new java.util.Date()))),
    500
  )
)

Enumerator is a PRODUCER of statically typed chunks of data.

Enumerator[E] produces chunks of data of type E and can be of the 3 following kinds:

  • Input[E] is a chunk of data of type E : for ex, Input[Pizza] is a chunk of Pizza.
  • Input.Empty means the enumerator is empty : for ex, an Enumerator streaming an empty file.
  • Input.EOF means the enumerator has reached its end : for ex, Enumerator streaming a file and reaching the end of file.

You can draw a parallel between the kinds of chunks and the states presented above (has more/no/no more elements).

Actually, Enumerator[E] contains Input[E] so you can put an Input[E] in it:

1
2
3
4
5
6
// create an enumerator containing one chunk of pizza
val pizza = Pizza("napolitana")
val enumerator: Enumerator[Pizza] = Enumerator.enumInput(Input.el(pizza))

// create an enumerator containing no pizza
val enumerator: Enumerator[Pizza] = Enumerator.enumInput(Input.Empty)

Enumerator is a non-blocking producer

The idea behind Play2 is, as you may know, to be fully non-blocking and asynchronous. Thus, Enumerator/Iteratee reflects this philosophy. The Enumerator produces chunks in a completely asynchronous and non-blocking way. This means the concept of Enumerator is not by default related to an active process or a background task generating chunks of data.

Remember the code snippet above with dateGenerator which reflects exactly the asynchronous and non-blocking nature of Enumerator/Iteratee?

1
2
3
4
5
6
7
8
9
// an Enumerator generated by a callback
// it generates a string containing current time every 500 milliseconds
// notice the Promise.timeout which provide a non-blocking mechanism
val dateGenerator: Enumerator[String] = Enumerator.generateM(
  play.api.libs.concurrent.Promise.timeout(
    Some("current time %s".format((new java.util.Date()))),
    500
  )
)

What’s a Promise?

It would require a whole article but let’s say the name corresponds exactly to what it does.
A Promise[String] means : ”It will provide a String in the future (or an error)”, that’s all. Meanwhile, it doesn’t block current thread and just releases it.

Enumerator requires a consumer to produce

Due to its non-blocking nature, if nobody consumes those chunks, the Enumerator doesn’t block anything and doesn’t consume any hidden runtime resources.
So, Enumerator MAY produce chunks of data only if there is someone to consume them.


So what consumes the chunks of data produced by Enumerator?
You have deduced it yourself: the Iteratee



><> About Iteratee ><>

Iteratee is a generic “stuff” that can iterate over an Enumerator

Let’s be windy for one sentence:

Iteratee is the generic translation of the concept of iteration in pure functional programming.
While Iterator is built from the collection over which it will iterate, Iteratee is a generic entity that waits for an Enumerator to be iterated over.

Do you see the difference between Iterator and Iteratee? No? Not a problem… Just remember that:

  • an Iteratee is a generic entity that can iterate over the chunks of data produced by an Enumerator (or something else)
  • an Iteratee is created independently of the Enumerator over which it will iterate and the Enumerator is provided to it
  • an Iteratee is immutable, stateless and fully reusable for different enumerators

That’s why we say:

An Iteratee is applied on an Enumerator or run over an Enumerator.

Do you remember the example above computing the total of all elements of an Enumerator[Int] ?
Here is the same code showing that an Iteratee can be created once and reused several times on different Enumerators.

1
2
3
4
5
6
7
8
9
10
11
12
val iterator = Iteratee.fold(0){ (total, elt) => total + elt }

val e1 = Enumerator(1, 234, 455, 987)
val e2 = Enumerator(345, 123, 476, 187687)

// we apply the iterator on the enumerator
e1(iterator)      // or e1.apply(iterator)
e2(iterator)

// we run the iterator over the enumerator to get a result
val result1 = e1.run(iterator) // or e1 run iterator
val result2 = e2.run(iterator)

Enumerator.apply and Enumerator.run are slightly different functions and we will explain that later.

Iteratee is an active consumer of chunks of data

By default, the Iteratee awaits a first chunk of data and immediately after, it launches the iteration mechanism. The Iteratee goes on consuming data until it considers it has finished its computation.
Once initiated, the Iteratee is fully responsible for the full iteration process and decides when it stops.

1
2
3
4
5
6
7
8
9
10
11
// creates the iteratee
val iterator = Iteratee.fold(0){ (total, elt) => total + elt }

// creates an enumerator
val e = Enumerator(1, 234, 455, 987)

// this injects the enumerator into the iteratee 
// = pushes the first chunk of data into the iteratee
enumerator(iterator)
// the iteratee then consumes as many chunks as it requires
// don't bother about the result of this, we will explain later

As explained above, the Enumerator is a producer of chunks of data and it expects a consumer to consume those chunks of data.
To be consumed/iterated, the Enumerator has to be injected/plugged into an Iteratee or more precisely the first chunk of data has to be injected/pushed into the Iteratee.
Naturally the Iteratee is dependent on speed of production of Enumerator: if it’s slow, the Iteratee is also slow.

Notice the relation Iteratee/Enumerator can be considered with respect to inversion of control and dependency injection pattern.

Iteratee is a ”1-chunk-loop” function

The Iteratee consumes chunks one by one until it considers it has ended iteration.
Actually, the real scope of an Iteratee is limited to the treatment of one chunk. That’s why it can be defined as a function being able to consume one chunk of data.

Iteratee accepts static typed chunks and computes a static typed result

Whereas an Iterator iterates over chunks of data coming from the collection that created it, an Iteratee is a bit more ambitious : it can compute something meanwhile it consumes chunks of data.

That’s why the signature of Iteratee is :

1
2
3
trait Iteratee[E, +A]
// E is the type of data contained in chunks. So it can only be applied on a Enumerator[E]
// A is the result of the iteration

Let’s go back to our first sample : compute the total of all integers produced by an Enumerator[Int]:

1
2
3
4
5
6
// creates the iteratee
val iterator = Iteratee.fold(0){ (total, elt) => total + elt }
val e = Enumerator(1, 234, 455, 987)

// runs the iteratee over the enumerator and retrieve the result
val total: Promise[Int] = enumerator run iterator

Notice the usage of run: You can see that the result is not the total itself but a Promise[Int] of the total because we are in an asynchronous world.
To retrieve the real total, you could use scala concurrent blocking Await._ functions. But this is NOT good because it’s a blocking API. As Play2 is fully async/non-blocking, the best practice is to propagate the promise using Promise.map/flatMap.

But a result is not mandatory. For ex, let’s just println all consumed chunks:

1
2
3
4
5
6
// creates the iteratee
val e = Enumerator(1, 234, 455, 987)
e(Iteratee.foreach( println _ ))
// or
e.apply(Iteratee.foreach( println _ ))
// yes here the usage of _ is so trivial that you shall use it

The result is not necessarily a primitive type, it can just be the concatenation of all chunks into a List for ex:

1
2
3
val enumerator = Enumerator(1, 234, 455, 987)

val list: Promise[List[Int]] = enumerator run Iteratee.getChunks[Int]

Iteratee can propagate the immutable context & state over iterations

To be able to compute final total, the Iteratee needs to propagate the partial totals along iteration steps.
This means the Iteratee is able to receive a context (the previous total for ex) from the previous step, then compute the new context with current chunk of data (new total = previous total + current element) and can finally propagate this context to the next step (if there need to be a next step).

Iteratee is simply a state machine

Ok this is cool but how does the Iteratee know it has to stop iterating?
What happens if there were an error/ EOF or it has reached the end of Enumerator?
Therefore, in addition to the context, the Iteratee should also receive previous state, decides what to do and potentially computes the new state to be sent to next step.

Now, remember the classic iteration states described above. For Iteratee, there are almost the same 2 possible states of iteration:

  • State Cont : the iteration can continue with next chunk and potentially compute new context
  • State Done : it signals it has reached the end of its process and can return the resulting context value

and a 3rd one which seems quite logical:

  • State Error : it signals there was an Error during current step and stops iterating

From this point of view, we can consider the Iteratee is just a state machine in charge of looping over state Cont until it detects conditions to switch to terminal states Done or Error.

Iteratee states Done/Error/Cont are also Iteratee

Remember, the Iteratee is defined as a 1-chunk-loop function and it’s main purpose is to change from one state to another one. Let’s consider those states are also Iteratee.

We have 3 ”State” Iteratees:

Done[E, A](a: A, remaining: Input[E])

  • a:A the context received from previous step
  • remaining: Input[E] representing the next chunk

Error[E](msg: String, input: Input[E])

Very simple to understand also: an error message and the input on which it failed.


Cont[E, A](k: Input[E] => Iteratee[E, A])

This is the most complicated State as it’s built from a function taking an Input[E] and returning another Iteratee[E,A]. Without going too deep in the theory, you can easily understand that Input[E] => Iteratee[E, A] is simply a good way to consume one input and return a new state/iteratee which can consume another input and return another state/iteratee etc… till reaching state Done or Error.
This construction ensures feeding the iteration mechanism (in a typical functional way).

Ok lots of information, isn’t it? You certainly wonder why I explain of all of that? This is just because if you understand that, you will understand how to create an custom Iteratee.

Let’s write an Iteratee computing the total of the 2 first elements in an Enumerator[Int] to show an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Defines the Iteratee[Int, Int]
def total2Chunks: Iteratee[Int, Int] = {
  // `step` function is the consuming function receiving previous context (idx, total) and current chunk
  // context : (idx, total) idx is the index to count loops
  def step(idx: Int, total: Int)(i: Input[Int]): Iteratee[Int, Int] = i match {
    // chunk is EOF or Empty => simply stops iteration by triggering state Done with current total
    case Input.EOF | Input.Empty => Done(total, Input.EOF)
    // found one chunk 
    case Input.El(e) =>
      // if first or 2nd chunk, call `step` again by incrementing idx and computing new total
      if(idx < 2) Cont[Int, Int](i => step(idx+1, total + e)(i))
      // if reached 2nd chunk, stop iterating
      else Done(total, Input.EOF)
  }

  // initiates iteration by initialize context and first state (Cont) and launching iteration
  (Cont[Int, Int](i => step(0, 0)(i)))
}

// Using it
val promiseTotal = Enumerator(10, 20, 5) run total2Chunks
promiseTotal.map(println _)
=> prints 30

With this example, you can understand that writing an Iteratee is not much different than choosing what to do at each step depending on the type of Chunk you received and returning the new State/Iteratee.



A few candy for those who did not drown yet

Enumerator is just a helper to deal with Iteratee

As you could see, in Iteratee API, there is nowhere any mention about Enumerator.
This is just because Enumerator is just a helper to interact with Iteratee: it can plug itself to Iteratee and injects the first chunk of data into it.
But you don’t need Enumerator to use Iteratee even if this is really easier and well integrated everywhere in Play2.


Difference between Enumerator.apply(Iteratee) and Enumerator.run(Iteratee)

Let’s go back to this point evoked earlier. Have a look at the signature of main APIs in Enumerator:

1
2
3
4
5
6
trait Enumerator[E] {

  def apply[A](i: Iteratee[E, A]): Promise[Iteratee[E, A]]
  ...
  def run[A](i: Iteratee[E, A]): Promise[A] = |>>>(i)
}

apply returns last Iteratee/State

The apply function injects the Enumerator into the Iteratee which consumes the chunks, does its job and returns a Promise of Iteratee. From previous explanation, you may deduce by yourself that the returned Iteratee might simply be the last state after it has finished consuming the chunks it required from Enumerator.

run returns a Promise[Result]

run has 3 steps:

  1. Call previous apply function
  2. Inject Input.EOF into Iteratee to be sure it has ended
  3. Get the last context from Iteratee as a promise.

Here is an example:

1
2
3
4
5
6
7
8
9
// creates the iteratee
val iterator = Iteratee.fold(0){ (total, elt) => total + elt }
val e = Enumerator(1, 234, 455, 987)

// just lets the iterator consume all chunks but doesn't require result right now
val totalIteratee: Promise[Iteratee[Int, Int]] = enumerator apply iterator

// runs the iteratee over the enumerator and retrieves the result as a promise
val total: Promise[Int] = enumerator run iterator

To Remember

When you need the result of Iteratee, you shall use run

When you need to apply an Iteratee over an Enumerator without retrieving the result, you shall use apply


Iteratee is a Promise[Iteratee] (IMPORTANT TO KNOW)

One more thing to know about an Iteratee is that Iteratee is a Promise[Iteratee] by definition.

1
2
3
4
5
6
7
8
9
10
// converts a Promise[Iteratee] to Iteratee
val p: Promise[Iteratee[E, A]] = ...
val it: Iteratee[E, A] = Iteratee.flatten(p)

// converts an Iteratee to a Promise[Iteratee]
// pure promise
val p1: Promise[Iteratee[E, A]] = Promise.pure(it)
// using unflatten
val p2: Promise[Iteratee[E, A]] = it.unflatten.map( _.it )
// unflatten returns a technical structure called Step wrapping the Iteratee in _.it

Iteratee <=> Promise[Iteratee]

This means that you can build your code around Iteratee in a very lazy way : with Iteratee, you can switch to Promise and back as you want.



Final words about Enumeratee

You discovered Iteratee, then Enumerator
And now you come across this… Enumeratee???
What is that new stuff in XXXtee ?????

2nd advice : DON’T PANIC NOW… Enumeratee concept is really simple to understand

Enumeratee is just a pipe adapter between Enumerator and Iteratee


Imagine you have an Enumerator[Int] and an Iteratee[String, Lis[String]].
You can transform an Int into a String, isn’t it?
So you should be able to transform the chunks of Int into chunks of String and then inject them into the Iteratee.

Enumeratee is there to save you.

1
2
3
4
val enumerator = Enumerator(123, 345, 456)
val iteratee: Iteratee[String, List[String]] = 

val list: List[String] = enumerator through Enumeratee.map( _.toString ) run iteratee

What happened there?

You just piped Enumerator[Int] through and Enumeratee[Int, String] into Iteratee[String, List[String]]

In 2 steps:

1
2
val stringEnumerator: Enumerator[String] = enumerator through Enumeratee.map( _.toString )
val list: List[String] = stringEnumerator run iteratee

So, you may understand that Enumeratee is a very useful tool to convert your custom Enumerator to be used with generic Iteratee provided by Play2 API.
You’ll see that this is certainly the tool you will use the most while coding with Enumerator / Iteratee.

Enumeratee can be applied to an Enumerator without Iteratee

This is a very useful feature of Enumeratee. You can transform Enumerate[From] into Enumerator[To] with an Enumeratee[From, To]

Signature of Enumeratee is quite explicit:

1
Enumeratee[From, To]

So you can use it as following:

1
val stringEnumerator: Enumerator[String] = enumerator through Enumeratee.map( _.toString )

Enumeratee can transform an Iteratee

This is a bit stranger feature because you can transform an Iteratee[To, A] to an Iteratee[From, A] with Enumeratee[From, To]

1
2
3
val stringIteratee: Iteratee[String, List[String]] = 

val intIteratee: Iteratee[Int, List[String]] = Enumeratee.map[Int, String]( _.toString ) transform stringIteratee

Enumeratee can be composed with an Enumeratee

Yes, this is the final very useful feature of Enumeratee.

1
2
3
4
val enumeratee1: Enumeratee[Type1, Type2] = 
val enumeratee2: Enumeratee[Type2, Type3] = 

val enumeratee3: Enumeratee[Type1, Type3] = enumeratee1 compose enumeratee2

So once again, very easy to see that you can create your generic Enumeratees and then compose them into the custom Enumeratee you need for your custom Enumerator / Iteratee.


Conclusion

Now I hope you have a bit more information and are not lost anymore.
Next step is to use Iteratee / Enumerator / Enumeratee all together.
I’ll write other articles presenting more specific and practical ideas and concepts and samples…
There are a lot of interesting features that are worth precise explanations.
Understanding clearly what’s an Iteratee is important because it helps writing new Iteratees but you can also stay superficial and use the many helpers provided by Play2 Iteratee API.

Ok, documentation is not yet as complete as it should but we are working on this!!!

Anyway, why should I use Iteratee / Enumerator / Enumeratee ?

I want to tell you that Iteratee / Enumerator / Enumeratee is not a funny tool for people found of functional constructions. They are useful in many domains and once you will understand how they work, I can promise you that you will begin to use it more and more.

Modern web applications are not only dynamically generated pages anymore. Now you manipulate flows of data coming from different sources, in different formats, with different availability timing. You may have to serve huge amount of data to huge number of clients and to work in distributed environments.

Iteratee are made for those cases because there are safe, immutable and very good to deal with data flows in realtime. Let’s tell the buzzword you can see more & more “Realtime WebApp” and Iteratee is associated to that ;)

Note on weird operators

You will certainly see lots of those operators in code based on Iteratee / Enumerator / Enumeratee such as &>, |>>, |>>> and the famous fish operator ><>. Don’t focus on those operators right now, there are just aliases of real explicit words such as through, apply, applyOn or compose. I’ll try to write an article about those operators to demystify them. With practice, some people will find the code with operators clearer and more compact, some people will prefer words.

Have fun

XML/SOAP to/from scala structures with xmlsoap-ersatz

xmlsoap-ersatz is a toolset to help people serialize/deserialize XML/SOAP with Scala. It doesn’t try to respect any standard but it allows to interprete and generate any XML format with any standard you require.

It was developed to be used with Play2/Scala but it can work standalone as it doesn’t depend on any other library.

xmlsoap-ersatz uses the same design as Play2 Json serialization/deserialization based on implicit typeclasses. This mechanism is very clean, robust and generic. Please note that implicits are NOT used as implicit CONVERSIONS which are often tricky and sometimes dangerous!

xmlsoap-ersatz is still draft library so if you discover anything wrong, don’t hesitate to tell it

xmlsoap-ersatz is an opensource public github so don’t hesitate to contribute and give ideas :)

Full doc is in Github Wiki


XML Scala serialization/deserialization

Imagine you want to map this XML to a case class

val fooXml = <foo>
    <id>1234</id>
    <name>brutus</name>
    <age>23</age>
</foo>

You want to map it to:

case class Foo(id: Long, name: String, age: Option[Int])
Foo(id=1234L, name="brutus", age=Some(23))
  • case class is a sample but the mechanism also works with any structure in Scala such as tuples
  • age field is Option[Int] meaning it might not appear in the XML (None in this case)

So how would you write that with xmlsoap ersatz?

import play2.tools.xml._
import play2.tools.xml.DefaultImplicits._
[...]
val foo = EXML.fromXML[Foo](fooXml)
assert(foo == Foo(1234L, "brutus", Some(23)))

val fooXml2 = EXML.toXML(foo)
assert(fooXml2 == fooXml)

As you may imagine, this is not so simple as fromXML/toXML signatures are the following:

object EXML {
    def toXML[T](t: T, base: xml.NodeSeq = xml.NodeSeq.Empty)(implicit w: XMLWriter[T]): xml.NodeSeq
    def fromXML[T](x: xml.NodeSeq)(implicit r: XMLReader[T]): Option[T] 
}

You can see the implicit typeclasses XMLReader/XMLWriter which define the mapper to/from XML to your case class. So in order EXML.fromXML/EXML.toXML to work properly, you should define an implicit XML reader/writer for your specific structure in your scope. It can be done at once by extending XMLFormatter[T]:

trait XMLFormatter[T] extends XMLReader[T] with XMLWriter[T] {
    def read(x: xml.NodeSeq): Option[T]
    def write(f: T, base: xml.NodeSeq): xml.NodeSeq
}

Defining the implicit for your case class

implicit object FooXMLF extends XMLFormatter[Foo] {
  def read(x: xml.NodeSeq): Option[Foo] = {
    for( 
      id <- EXML.fromXML[Long](x \ "id");
      name <- EXML.fromXML[String](x \ "name");
      age <- EXML.fromXML[Option[Int]](x \ "age")
    ) yield(Foo(id, name, age))
  }

  def write(f: Foo, base: xml.NodeSeq): xml.NodeSeq = {
    <foo>
      <id>{ f.id }</id>
      <name>{ f.name }</name>
      { EXML.toXML(f.age, <age/>) }
    </foo>
  }
}

You may think this is a bit tedious to write but this is quite easy after a few tries and the most important:

This mechanism provides a very precise and simple control on what you want to do.

Please note:

  • the write function uses Scala XML literals simply.
  • the implicit is important: you can declare it once in your scope and that’s all.
  • the age field in write requires a special syntax:

    { EXML.toXML(f.age, <age/>) } means: <age/> is used as the base node and will generate following XML:

    • if age is Some(23): <age>23</age>
    • if age is None: <age xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" /> (standards defines this but you can redefine it as you want)
  • the base field in write function can be used to pass a parent context node to the writer. It is helpful in case you need to add attributes to parent node for ex as in the case of age: Option[Int] field.

    But don’t forget that Scala XML nodes are immutable and that you can just copy the nodes you pass to a function.

  • the for-comprehension is just a shortcut but you could write it using flatMap/map also:

For ex:

def read(x: xml.NodeSeq): Option[Foo] = {
  EXML.fromXML[Long](x \ "id").flatMap{ id =>
    EXML.fromXML[String](x \ "name").flatMap { name =>
      EXML.fromXML[Int](x \ "age").map{ age =>
        Foo(id, name, age)
      }
    }
  }
}

The complete code

import play2.tools.xml._
import play2.tools.xml.DefaultImplicits._

implicit object FooXMLF extends XMLFormatter[Foo] {
  def read(x: xml.NodeSeq): Option[Foo] = {
    for( 
      id <- EXML.fromXML[Long](x \ "id");
      name <- EXML.fromXML[String](x \ "name");
      age <- EXML.fromXML[Option[Int]](x \ "age");
    ) yield(Foo(id, name, age))
  }

  def write(f: Foo, base: xml.NodeSeq): xml.NodeSeq = {
    <foo>
      <id>{ f.id }</id>
      <name>{ f.name }</name>
      { EXML.toXML(f.age, <age/>) }
    </foo>
  }
}

val foo = EXML.fromXML[Foo](fooXml)
assert(foo == Foo(1234L, "albert", 23)

val fooXml = EXML.toXML(foo)
assert(fooXml == fooXml)

Integrate with Play2/Scala

Add xmlsoap-ersatz to your configuration (ersatz is deployed as a maven repo on github)

object ApplicationBuild extends Build {

  val appName         = "play2-xmlsoap"
  val appVersion      = "1.0-SNAPSHOT"

  val appDependencies = Seq(
    "play2.tools.xml" %% "xmlsoap-ersatz" % "0.1-SNAPSHOT"
  )  

  val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
    resolvers += ("mandubian-mvn snapshots" at "https://github.com/mandubian/mandubian-mvn/raw/master/snapshots")
  )
}

Use xmlsoap-ersatz in your controller

package controllers

import play.api._
import play.api.mvc._
import play2.tools.xml._
import play2.tools.xml.DefaultImplicits._

object Application extends Controller {
   case class Foo(id: Long, name: String, age: Option[Int])

   implicit object FooXMLF extends XMLFormatter[Foo] {
      def read(x: xml.NodeSeq): Option[Foo] = {
      for( 
          id <- EXML.fromXML[Long](x \ "id");
          name <- EXML.fromXML[String](x \ "name");
          age <- EXML.fromXML[Option[Int]](x \ "age")
        ) yield(Foo(id, name, age))
      }

      def write(f: Foo, base: xml.NodeSeq): xml.NodeSeq = {
        <foo>
          <id>{ f.id }</id>
          <name>{ f.name }</name>
          { EXML.toXML(f.age, <age/>) }
        </foo>
     }
  }  

  def foo = Action(parse.xml) { request =>
    EXML.fromXML[Foo](request.body).map { foo =>
      Ok(EXML.toXML(foo))
    }.getOrElse{
      BadRequest("Expecting Foo XML data")
    }
  }

}

Finally the route in conf/routes

POST    /foo    controllers.Application.foo

Have fun and don’t hesitate to contribute