Get a String from a JSon request - json

i'm writing a Play 2.3.2 application in Scala.
I'm writing a Statistic controller that queries my mongodb database for obtain some informations.
Now i'm trying to implement a method that returns all the tags associate to a user.
I get an http request in json format as the following:
{
"user": "example#example.com"
}
I want to parse the Json request and get the String associate to the "user" field of the Json, if the Json is correctly i want to do some work with the String object, otherwise i want to return a BadRequest response.
My method implementation is something like this:
def userEmail = Action.async { request =>
val userEmail: String = request.body.asJson.map { json =>
json.validate[String].map {
//if the json congaing the "user tag" return the instance, get the instance, otherwise return a BadRequestInstance
}
}
def elaborate(user: String)= {
//some work
}
elaborate(userEmail)
}
How can i make that??

As johanandren mentioned reading playframework documentation should solve your problem.
Hint: I would define case class and implicit reads to convert json data into case class type.
case class User(email: String)
implicit val userReads = (
(JsPath \ "email").read[String]
)(User.apply _)

Related

Scala Slick: how to serialize the result of a query to a variable table

I would like to provide a select method to a controller that takes a table name as parameter and returns the result of the SELECT query as JSON. So far I have done this:
def specialSelect(tableName: String) = Action.async {
val tq: TableQuery[_] = tableObjectFactory(tableName)
val res: Future[Seq[_]] = db.run(tq.result)
res.map { p:Seq[_] => Ok(p.toJson) }
}
where tableObjectFactory takes my table name and returns a TableQuery of the specific type:
def tableObjectFactory(tableName: String): TableQuery[_] = {
tableName match {
case "users" => TableQuery[Users]
case "projects" => TableQuery[Projects]
}
}
If fails because there is no JSON serializer defined for a a generic Seq[_] (actually _ should be a Product with Serializable, not sure if that helps).
The table name is not known in advance (found in the URL, such as in "/special_select/<tableName>"), and I have 120 such tables so I can't just implement it for each table.
Is there a way to serialize any Seq[_], knowing that the _ is always a Slick row result (e.g. a case class UsersRow), whatever the table is?
I have read about Generic DAOs and ActiveSlick, but I am not sure if should go so far.
Gson worked, thanks #pamu. Add
libraryDependencies += "com.google.code.gson" % "gson" % "2.8.0"
to build.sbt, then this will convert any Seq[_] or rows to a JsArray that can be given as http response:
import com.google.gson.Gson
import play.api.libs.json._
val gson: Gson = new Gson()
def slickToJson(res: Seq[_]): JsArray = {
JsArray(res.map(gson.toJson).map(Json.parse))
}
// in controller Action.async:
db.run(...).map(p => Ok(slickToJson(p)))
Rows are serialized to String by Gson, then parsed back to JsObjects by Play api, then put in a JsArray. I couldn't find better.

type mismatch; found : scala.collection.immutable.Stream[String] required: String in Play Scala?

I am trying to display json data from database using scala/anorm of Play(2.2.x), If I give the following trial, I am getting the error like: type mismatch; found : scala.collection.immutable.Stream[String] required: String, but If I write like: sql().map(row => rowString).toString - is giving Stream type json data(i don't need it), so how can I get my normal json data for it ? Please help me and thank in advance.
contorller:
class Test extends Controller {
def getTest = Action {
var sql: SqlQuery = SQL("select name::TEXT from test");
def values: String = DB.withConnection { implicit connection =>
sql().map(row => row[String]("name"))//giving error: type mismatch; found : scala.collection.immutable.Stream[String] required: String
}
Ok(values)
}
It looks like you are using Anorm for database access. As noted in the comments above, executing the Anorm query returns a Stream rather than just a value. When you map the value, it is again returning a Stream of String so that the results can be processed as a stream. This is very useful for large result sets where it makes more sense to process the stream incrementally and stream the result to the client. It looks like you are just getting started so you probably don't want to worry about that right now.
You can covert the result from a stream into a conventional list by simply using toList:
val resList = sql().map(row => row[String]("name")).toList
Now, you also need to unescape the string and return it as a JSON result. That can be done by using string interpolations. To do this, you just need to surround the String in a StringContext and call the s method with no arguments.
val newResList = resList.map(s => StringContext(s).s())
Finally, you should actually be converting the String into a PlayJson JsValue type so that your controller is actually returning the right type.
Json.parse(newResList.mkString("[",",","]")
The mkString method is used to convert the list into a valid JSON string. You will need to import play.api.libs.json.Json for this to work. Passing a JsValue to Ok ensures that the mime type of the response is set to "application/json". You can learn more about using JSON with play here. This will be important if you intend to build JSON services.
Putting it together, you get the following:
class Test extends Controller {
def getTest = Action {
var sql: SqlQuery = SQL("select name::TEXT from test");
def values: JsValue = DB.withConnection { implicit connection =>
val resList = sql().map(row => row[String]("name")).toList
val newResList = resList.map(s => StringContext(s).s())
Json.parse(newResList.mkString("[",",","]")
}
Ok(values)
}
You could also use the following alternate structure to simplify and get rid of the rather sloppy mkString call.
class Test extends Controller {
def getTest = Action {
var sql: SqlQuery = SQL("select name::TEXT from test");
def values: JsValue = DB.withConnection { implicit connection =>
val resList = sql().map(row => row[String]("name")).toList
Json.toJson(resList.map(s => Json.parse(StringContext(s).s())))
}
Ok(values)
}
This parses each of the JSON strings in the list and then converts the list into JsArray again using the capabilities of Play's built in JSON library.

Play Framework Json Validation

I'm trying to parse a json structure, validate it and use the validated result.
def createEntry = Action(parse.tolerantJson) { request =>
request.body.validate[MyJson].map { myJson =>
// do something with the MyJson object
}.recoverTotal { err => BAD_REQUEST }
The MyJson object looks like this:
case class MyJson(
complexType: ComplexType,
strs: Seq[String],
maps: Map[String, ComplexType]
)
case class ComplexType(
str1: String,
bool1: Boolean,
cxType2: ComplexType2,
maps: Map[String, String]
)
case class ComplexType2(str: String, strs: Seq[String])
Would the validate method automatically try to box the JSON string into the object type? os Should I write an additional body parser?
Assuming you have the appropriate Format or Reads objects in scope for MyJson, yes, response.body.validate will automatically parse the JSON string into a MyJson instance, only entering the recoverTotal block if the JSON validation fails (i.e., the JSON in the request cannot be parsed into a MyJson, even if it is a valid JSON string).

How to respond with a pretty-printed JSON object using play framework?

How can one send, using the Play! framework, a JSON response that is formatted to be human-readable?
For example, I'm looking for something like:
def handleGET(path:String) = Action{ implicit request =>
val json = doSomethingThatReturnsAJson(path,request)
request.getQueryString("pretty") match {
case Some(_) => //some magic that will beautify the response
case None => Ok(json)
}
}
My search led me to JSON pretty-print, which was not very helpful on it's own, but it did say the ability should be integrated in future versions. That was play 2.1.X, so, I guess it already exists somewhere in the 2.2X version of play?
Play framework has pretty printing support built-in:
import play.api.libs.json.Json
Json.prettyPrint(aJsValue)
So in your case, it would be sufficient to do the following:
def handleGET(path:String) = Action { implicit request =>
val json = doSomethingThatReturnsAJson(path, request)
request.getQueryString("pretty") match {
case Some(_) => Ok(Json.prettyPrint(json)).as(ContentTypes.JSON)
case None => Ok(json)
}
}
You can use Gson to pretty print Json string, don't know about scala; but here is a Java example which you can convert to scala and use it:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonStr = gson.toJson(obj);
System.out.println(jsonStr);

Handling JSON requests in Play Framework 2.0 Scala

I am trying to send data from the client to the server using a JSON request. The body of the JSON request looks like this:
{
"upload":
{
"ok":"some message",
"assemblyId":"a9d8f72q3hrq982hf98q3"
}
}
Play is able to recognize the request body as JSON but when I try to parse individual values, namely the "upload" object, Play complains that it can't find the specified parameter.
The Scala method is as follows:
def add(course:Long) = withAccount { account => implicit request =>
println()
println(request.body) // output: AnyContentAsJson({"upload":{"ok":"ASSEMBLY_COMP...
request.body.asJson.map { json =>
println()
println(json) // output: {"upload":{"ok":"ASSEMBLY_COMPLETED","assemb...
(json \ "upload").asOpt[models.SomeClass].map { upload =>
Ok("Got upload")
}.getOrElse {
BadRequest("Missing parameter [upload]")
}
}.getOrElse {
BadRequest("Expecting Json data")
}
}
I'm having trouble understanding why the above code fails. The method has no trouble mapping the request body to a json object. The "println(json)" command prints out the exact same thing that Chrome shows me as the 'Request Payload'. Yet, when I try to grab the root object, "upload", it fails. And the method returns a bad request complaining about the missing parameter.
To do asOpt[models.SomeClass] there needs to be a Reads instance for it to work.
Here is an example
case class SomeClass(ok: String, assemblyId: String)
implicit object SomeClassReads extends Reads[SomeClass] {
def reads(json: JsValue) =
SomeClass((json \ "ok").as[String], (json \ "assemblyId").as[String])
}
You can see how you would implement a Reads instance at
https://github.com/playframework/Play20/blob/2.0.x/framework/src/play/src/main/scala/play/api/libs/json/Reads.scala#L35
If you use play 2.1x, Reads has changed a bit from 2.0x and it's probably your main problem(like me).
You can find a very good explanation here.
Simply this code works fine:
import play.api.libs.json._
import play.api.libs.functional.syntax._
case class Person(name: String, age: Int, lovesChocolate: Boolean)
implicit val personReads = Json.reads[Person]
It look amazing isn't it? But there are some points that you should pay attention:
Implicit definition should be in controller. Of course there are some other ways to do it.
If your model is in models class(it's in controller at the example above) you shouldn't name your object same with your class. In that case it doesn't work:
case class Person(name: String, age: Int, lovesChocolate: Boolean)
object Person{....} //this won't work
This way have big advantages. I strongly recommend you to check out this blog.