Search code examples
scalaplayframework-2.0playframework-json

How to trim a JsArray in Scala Play Framework 2.1 using transformers


To reduce network traffic to Internet clients from an internal webservice which I cannot change, I want to trim down the JSON response.

So a webservice "relay" which extracts only a specific subset of the JSON response.

Since all that is occurring is transforming JSON from one format to another, I would prefer to use the new JSON Transformers in Play Framework 2.1 (see: http://www.playframework.com/documentation/2.1.1/ScalaJsonTransformers)

To increase the difficulty, the response is an array of differing JSON objects, on which only two fields are required from each object.

As a specific dummy example, I am attempting to convert the following JSON:

[
  {
    "keyA": "keep this value",
    "keyB": [ {"value": "keep this value", "anotherValue": "keep this value" } ],
    "keyC": "drop this value"
  },
  {
    "keyA": "keep this value",
    "keyB": [ {"value": "keep this value", "anotherValue": "keep this value" } ],
    "keyD": "drop this value",
    "keyE": "drop this value"
  },
  {
    "keyA": "keep this value",
    "keyB": [ {"value": "keep this value", "anotherValue": "keep this value" } ],
    "extraRandomKeys": "drop this value",
    "fieldsWhichMayNotAlwaysAppear: "drop this value"
  }
]

into:

[
  {
    "keyA": "keep this value",
    "keyB": [ {"value": "keep this value", "anotherValue": "keep this value" } ]
  },
  {
    "keyA": "keep this value",
    "keyB": [ {"value": "keep this value", "anotherValue": "keep this value" } ]
  },
  {
    "keyA": "keep this value",
    "keyB": [ {"value": "keep this value", "anotherValue": "keep this value" } ]
  }
]

The template method I've used is:

def relayWsResponse = Action {
  request =>
    Async {
      WS.url("http://internalhost/service")
        .get()
        .map(
        response => {
          Ok(
            response.json.transform(
              ???
            ).get
          )
        }
      )
    }
}

Solution

  • It works, but probably it's not best option:

    import play.api.libs.json._
    import play.api.libs.json.Reads._
    import play.api.libs.functional.syntax._
    
    val transformer: Reads[JsArray] = of[JsArray].map{
      case JsArray(xs) => JsArray(xs.flatMap{
        case x: JsObject => Some(
          x.transform(
            (__ \ "keyA").json.pickBranch and (__ \ "keyB").json.pickBranch reduce
          ).get
        )
      })
    }