Play Framework Json Validation - json

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).

Related

How to know which field is missed while parsing json in Json4s

I have made a generic method which parses json to case class and it also works fine. But if tries to parse big json which have one or two mandatory field then I am not able to figure out which particular mandatory f ield is missing. I am only able to handle it with IllegalArgumentException. Is there a way to handle to know which is field is missing while parsing Json by using json4s.
Here is my code ->
object JsonHelper {
implicit val formats: DefaultFormats = DefaultFormats
def write[T <: AnyRef](value: T): String = jWrite(value)
def parse(value: String): JValue = jParser(value)
}
And this is the method I am using to parse Json and handle failed case ->
def parseJson[M](json: String)(implicit m: Manifest[M]): Either[ErrorResponse, M] = {
try
Right(JsonHelper.parse(json).extract[M])
catch {
case NonFatal(th) =>
th.getCause.getCause match {
case e: java.lang.IllegalArgumentException =>
error(s"Invalid JSON - $json", e)
Left(handle(exception = EmptyFieldException(e.getMessage.split(":").last)))
case _ =>
error(s"Invalid JSON - $json", th)
Left(handle(exception = new IllegalArgumentException("Invalid Json", th)))
}
}
}
Like for a Json ->
{
"name": "Json"
}
And case class ->
case class(name: String, profession: String)
if I try to parse above json into case class currently I am getting Invalid JSON - IllegalArgumentException. But is there a way that the exception tells which is field is missing like in above example "profession" is missing.
Is there a way to handle to know which is field is missing while parsing Json by using json4s.
Maybe you have more complicated setting, but for example for
import org.json4s._
import org.json4s.jackson.JsonMethods._
val str = """{
| "name": "Json"
|}""".stripMargin
val json = parse(str) // JObject(List((name,JString(Json))))
implicit val formats: Formats = DefaultFormats
case class MyClass(name: String, profession: String)
json.extract[MyClass]
it produces
org.json4s.MappingException: No usable value for profession
Did not find value which can be converted into java.lang.String
at org.json4s.reflect.package$.fail(package.scala:56)
at ...
with the name of missing field and if the class is just case class MyClass(name: String) then this produces MyClass(Json).
If the class is case class MyClass(name: String, profession: Option[String]) then this produces MyClass(Json,None).
So normally IllegalArgumentException should be followed by Caused by: org.json4s.MappingException with the field name. I guess now you're swallowing json4s MappingException somewhere. Maybe in th.getCause.getCause match .... It's hard to say without MCVE.

How to convert response body in Json using play framework

override def accessToken(): ServiceCall[RequestTokenLogIn, Done] = {
request=>
val a=request.oauth_token.get
val b=request.oauth_verifier.get
val url=s"https://api.twitter.com/oauth/access_token?oauth_token=$a&oauth_verifier=$b"
ws.url(url).withMethod("POST").get().map{
res=>
println(res.body)
}
The output which I am getting on terminal is
oauth_token=xxxxxxxxx&oauth_token_secret=xxxxxxx&user_id=xxxxxxxxx&screen_name=xxxxx
I want to convert this response in json format.like
{
oauth_token:"",
token_secret:"",
}
When Calling res.json.toString its not converting into jsValue.
Is there any other way or am I missing something?
According to the documentation twitter publishes, it seems that the response is not a valid json. Therefore you cannot convert it automagically.
As I see it you have 2 options, which you are not going to like. In both options you have to do string manipulations.
The first option, which I like less, is actually building the json:
print(s"""{ \n\t"${res.body.replace("=", "\": \"").replace("&", "\"\n\t\"")}" \n}""")
The second option, is to extract the variables into a case class, and let play-json build the json string for you:
case class TwitterAuthToken(oauth_token: String, oauth_token_secret: String, user_id: Long, screen_name: String)
object TwitterAuthToken {
implicit val format: OFormat[TwitterAuthToken] = Json.format[TwitterAuthToken]
}
val splitResponse = res.body.split('&').map(_.split('=')).map(pair => (pair(0), pair(1))).toMap
val twitterAuthToken = TwitterAuthToken(
oauth_token = splitResponse("oauth_token"),
oauth_token_secret = splitResponse("oauth_token_secret"),
user_id = splitResponse("user_id").toLong,
screen_name = splitResponse("screen_name")
)
print(Json.toJsObject(twitterAuthToken))
I'll note that Json.toJsObject(twitterAuthToken) returns JsObject, which you can serialize, and deserialize.
I am not familiar with any option to modify the delimiters of the json being parsed by play-json. Given an existing json you can manipulate the paths from the json into the case class. But that is not what you are seeking for.
I am not sure if it is requires, but in the second option you can define user_id as long, which is harder in the first option.

Get a String from a JSon request

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 _)

Map a nested JSON payload to a struct in Elixir

I am attempting to port the Golang tutorial geddit to Elixir. I have done so successfully with Dartlang, but Elixir's operations on maps & lists are confusing for me.
Using HTTPoison and JSEX, I have the following code:
defmodule Redditex do
use HTTPoison.Base
def process_url(url) do
"http://www.reddit.com/r/#{url}.json"
end
def process_response_body(body) do
json = JSEX.decode! body
json = Enum.map json, fn ({k, v}) -> {String.to_atom(k), v } end
json
end
end
My difficulty is parsing the JSON body into an appropriate struct where the JSON contains nested data. Jazz has some allusion to mapping to a structure but not with nested data.
Is there an example or a common practice to decode JSON in Elixir similar to Go's usage:
type Response struct {
Data struct {
Children []struct {
Data Item
}
}
}
type Item struct {
Title string
URL string
Comments int `json:"num_comments"` #mapping to another field label
}
Using the Poison JSON library I was able to get partly there for handling the nesting:
def handle_response(%{status_code: 200, body: body}) do
json = Poison.decode!(body, as: %{"data" => %{"children" => [%{"data" => Redditex.Item}]}})
items = Enum.map( json["data"]["children"], fn (x) -> x["data"] end )
end
Enumertion is necessary to remove the anonymous structs and the remapping of the field names has not shown as a native solution. A work path forward nonetheless.

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.