Reputation: 842
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"}))
^
Upvotes: 3
Views: 206
Reputation: 8673
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)
Upvotes: 5