scalaplayframework-2.0play-jsonplayframework-json

Retrieving a particular field inside objects in JsArray


A part of my JSON response looks like this:

"resources": [{
        "password": "",
        "metadata": {
            "updated_at": "20190806172149Z",
            "guid": "e1be511a-eb8e-1038-9547-0fff94eeae4b",
            "created_at": "20190405013547Z",
            "url": ""
        },
        "iam": false,
        "email": "<some mail id>",
        "authentication": {
            "method": "internal",
            "policy_id": "Default"
        }
    }, {
        "password": "",
        "metadata": {
            "updated_at": "20190416192020Z",
            "guid": "6b47118c-f4c8-1038-8d93-ed6d7155964a",
            "created_at": "20190416192020Z",
            "url": ""
        },
        "iam": true,
        "email": "<some mail id>",
        "authentication": {
            "method": "internal",
            "policy_id": null
        }
    },
    ...
]

I am using Json helpers provided by the Play framework to parse this Json like this:

val resources: JsArray = response("resources").as[JsArray]

Now I need to extract the field email from all these objects in the resources JsArray. For this I tried writing a foreach loop like:

for (resource <- resources) {

}

But I'm getting an error Cannot resolve symbol foreach at the <- sign. How do I retrieve a particular field like email from each of the JSON objects inside a JsArray


Solution

  • With Play JSON I always use case classes. So your example would look like:

    import play.api.libs.json._
    
    case class Resource(password: String, metadata: JsObject, iam: Boolean, email: String, authentication: JsObject)
    
    object Resource {
      implicit val jsonFormat: Format[Resource] = Json.format[Resource]
    }
    
    val resources: Seq[Resource] = response("resources").validate[Seq[Resource]] match {
      case JsSuccess(res, _) => res
      case errors => // handle errors , e.g. throw new IllegalArgumentException(..)
    }
    

    Now you can access any field in a type-safe manner.

    Of course you can replace the JsObjects with case classes in the same way - let me know if you need this in my answer.

    But in your case as you only need the email there is no need:

    resources.map(_.email) // returns Seq[String]