简体   繁体   中英

Iterating and reformatting an array in JSON with Play 2.1.1

I have trouble manipulating a Json array after parsing it.

I pass the following Json object in Javascript using the post method: [{"id":"someid"},{"id":"anotherid"}]

I have used Andy's setup ( Iterating over an array in JSON with Play 2.1.1 ) to parse json encoded arrays passed through using the post method (I moved the code into the controller for convenience)

  case class FBUser(
     id: String
  ){}
  object FBUser {
    /** Uses a Scala Macro to define the Reads function */
    implicit val userReads: Reads[FBUser] = Json.reads[FBUser]
    implicit val fbUserFormat:Format[FBUser] = Json.format[FBUser]
  }

  def doQuery = Action (parse.json){ implicit request =>

    val readIDFromInput =  (__).read[List[FBUser]]

    val IDs = request.body.validate(readIDFromInput)

    IDs.map(
      item => Ok(Json.toJson(item))
    ).recoverTotal{
      err => BadRequest(JsError.toFlatJson(err))
    }

  }

This works as it should: it reads and returns the Json object. I have trouble using the Json object to create new variables. In this case, I would like to construct a Json object like {["someid", "anotherid"]} (that is, without "id")

First I tried: item => Ok(Json.toJson(item.id)) // trying to access item.id

But this resulted in an error: value id is not a member of object controllers.ScalaPoster.FBUser

I tried adding a function to the object ( def getId():String = { return this.id } ). Accessing that ( item.getId() ) results in the same error.

All help is highly appreciated!

Edit (not enough reputation to answer my own question):

Adding another map function ( Json.toJson(list.map{ item => item.id } ) gives access to the id:

 case class FBUser(
     id: String
  )
  implicit val fbUserFormat:Format[FBUser] = Json.format[FBUser]

  def doQuery = Action (parse.json){ implicit request =>

    var idsValid = true
    var badReq = Json.obj();

      val readIDFromInput =  (__).read[List[FBUser]]

      val listIDs = request.body.validate(readIDFromInput).map {

        case list => Json.toJson(list.map{ item => item.id } )
      }.recoverTotal{
        e => {
          idsValid = false
          badReq = JsError.toFlatJson(e)  
          Json.arr() // empty array                                                                                          
        }
      }                                                                                                                                                                                                                      

    if( idsValid )
      Ok(listIDs)                                                                                                                                                                                                                         
    else                                                                                                                                                                                                                                    
      BadRequest("Detected error:"+ badReq)         
  }

Hope this may help others :)

As you already noticed, you had to use map twice: the first time to access the contents of the JsResult and once again to access the contents of the List inside that JsResult. This way, you gained access to the nested id you were looking for and came up with a viable solution.

However, I'd like to point out a fairly elegant solution that solves your problem without relying on mutable state:

request.body.validate(readIDFromInput) match {
  case JsSuccess(users, _) => Ok(users.map(_.id))
  case JsError(errors) => BadRequest(errors)
}

I match the validation to its two possible cases: either it passes and I return a 200 with the list of ids or it fails and I return a 400 with the errors.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM