Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the wrong while trying to parse Future response?

I have a function which will take a Token via ajax request. It will return a response a list of directories while the token is valid.

def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => checkToken(form.token).map(token => {
      val directories = Directories.all.map(directory => {
        Json.toJson(directory)
      })
      Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
    })
  )
}

While I run the above code It says [As ^ sign indicate the position the error found]

No Json serializer found for type scala.concurrent.Future[play.api.libs.json.JsValue]. Try to implement an implicit Writes or Format for this type.
Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
                                                                                                                                            ^
like image 696
testuser Avatar asked Jun 04 '26 07:06

testuser


1 Answers

Here is what I come up with

def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => for {
      (token, directories) <- checkToken(form.token) zip Directories.all
    } yield {
      val isTokenValid = token.isDefined
      val responseBody = Json.obj(
        "status" -> isTokenValid, 
        "message" -> {
          if (isTokenValid)
            Json.toJson(directories)
          else
            "Invalid token"
        }
      )
      Ok(responseBody)
    }
  )
}

asuming checkToken and Directories.all returns Future.

Your function needs to return Future[Result]. When you are folding, the first branch is correct

formWithErrors => Future.successful(BadRequest(formWithErrors.toString))

However in the second branch it seems like you started a new Future by calling Directories.all, and you want to serialize it and return as json. There is no serializer for Future[JsValue] as this makes no sense, it would have to block to get result. You need to somehow get to the values of both checkToken(form.token) and Directories.all.

You can do this as I did above, or for example like this:

form => {
  val futureToken = checkToken(form.token)
  val futureDirectories = Directories.all

  for {
    token <- futureToken
    directories <- futureDirectories
  } yield {
     // same code as above
  }
}

Notice that if you would inline futureToken and futureDirectories they would be executed serially.

Also note that you are converting your directory list to json twice.

Once here

val directories = Directories.all.map(directory => {
  Json.toJson(directory)
})

Asuming Directories.all returns Future[List[Directory]], then when you use map, the function you pass operates on List[Directory] so the variable should be named directories not directory. It will work, play easly converts list of anything convertible to json, no need to do it manually.

Second time you did it here

Json.toJson(directories)
like image 116
Łukasz Avatar answered Jun 07 '26 11:06

Łukasz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!