Unexpected Decoding of = in Controller - encoding

From the front-end, I'm performing a jQuery POST with the following data:
[{name: "Kevin", age: 100, favoriteOperator:"="}]
This POST hits /sample URL.
In my controller, I read in the POST's body using:
def submit = Action { implicit request =>
val maybeRequestAsFormUrlEncoded: Option[Map[String, Seq[String]]] =
request.body.asFormUrlEncoded
Printing out map shows:
Map([{"name" : "Kevin", "age" : 100, "favoriteOperator" :" -> List("}])
Why is my favoriteOperator showing up as " -> List(" rather than "="?

Quite sure asFormUrlEncoded expects input like:
queryString=abc,def
anotherQueryString=blabla
which then is transformed into your map as:
Map("queryString" -> List("abc", "def"), "anotherQueryString" -> List("blabla"))
(I'm actually not so sure if abc,def and blabla really are deserialized into a list, that idea just comes because you get a list in your sample). Anyways, important is that asFormUrlEncoded expects key-value pairs separated by a = sign, that's why your string is taken apart like that. See also http://en.wikipedia.org/wiki/Url_encoding.
You might want to look into Json deserializers in play, as your request has a Json format:
http://www.playframework.com/documentation/2.2.x/ScalaJson

Related

How to read JSON with unknown key in ReasonML?

I am writing a simple application that display dog images from Dog API. I used bs-json to make it a record and use it later. The list of breeds can be obtained by the API. The response looks like this.
{
"message": {
"breed": ["array of sub-breeds"],
"breed without subbreed": [],
...
},
"status": "success"
}
So the key is not known at the compile time. If I add it one by one, it would be some kind of hardcode. I only want breeds not sub-breeds. If possible, I would like an array of them.
[| "chihuahua", "golden retreiver", ... |] // Something like this so I can make a select input
I think you could just decode into a Js.Dict.t and then take its keys.
Something like:
let decodeBreeds: Js.Json.t => array(string) =
Json.Decode.(dict(id) |> map(Js.Dict.keys))

Checkbox lists in Play with Scala

I have ...
a Seq[RoleId] defining all roles that a user can get granted
a Userwith a property roles: Seq[RoleId], where the roles are those that the user has got granted
a Play controller preparing a form and providing the user (including her roles) and the Seq of available RoleIds to the html page as part of the form's data (including the mapping)
a Twirl template showing a checkbox for each available role
What I'd like to achieve is a list of checkboxes where every checkbox who's value is part of the user's roles is checked. So the list should show which of the available roles are granted to the user, as shown in this very refined prototype:
Name: [Doe, John]
Roles: [ ] Admin
[x] Manager
[x] Service Desk
[ ] Jack of all trades
if the user's name is John Doe with the roles Manager and Service Desk.
That seems rather simple, but I can't find a way to achieve it without some hacks (like circumventing the form and moving the role date to the Twirl template as a regular parameter; writing a custom mapper in the form handling code etc.). Isn't there a way to do it in the Play way without all that boilerplate ?
I googled hard, but I couldn't find any example that seemed to do it right. And Play's form processing docs weren't helpful either.
Any ideas ?
Upon refining my question I came up with a solution that worked.
I use the following form, which uses the case classes below to hold its data. As you can see there's a nested mapping inside, representing a list of roles and their state with regard to the user's roles (true meaning that the user has the role, false otherwise):
def userForm(implicit messages: Messages): Form[UserFormData] = Form(
mapping(
"firstName" -> nonEmptyText(minLength = 2, maxLength = 30),
"lastName" -> nonEmptyText(minLength = 2, maxLength = 40),
"email" -> email,
"roleAssignments" -> seq(
mapping(
"roleIdStr" -> nonEmptyText,
"isAssigned" -> boolean
)(RoleAssignment.apply)(RoleAssignment.unapply)
)
)(UserFormData.apply)(UserFormData.unapply)
)
case class UserFormData(firstName: String, lastName: String, email: String, roleAssignments: Seq[RoleAssignment])
case class RoleAssignment(roleIdStr: String, isAssigned: Boolean)
The controller just populates the form with data from the db:
def user(id: Long) = Action.async { implicit request =>
managerService.retrieveByIdWithRoles(id, Some(request.identity), request.remoteAddress).map { case (user, roles) =>
Ok(views.html.admin.administration.show_user(
userForm.fill(UserFormData(user.firstName, user.lastName, user.email, roleAssignments(roles)))))
}
}
private def roleAssignments(roles: Seq[Role]) = {
val roleIds = roles.map(_.id)
Roles.all.map { case id =>
RoleAssignment(id.toString, roleIds.contains(id))
}
}
And in the view template I repeat over the roleAssignments and use the index provided by repeatWithIndexto access the seq's elements:
#repeatWithIndex(userForm("roleAssignments")) { (roleAssignment, index) =>
#b4.checkbox(userForm(s"roleAssignments[$index].isAssigned"), '_text -> userForm(s"roleAssignments[$index].roleIdStr").value, '_custom -> true, 'readonly -> true)
}
Thank you #cchantep for pushing me to try harder.
The Play library provides an inputCheckboxGroup which works the same way as the inputRadioGroup.
In your Play controller:
def userForm(implicit messages: Messages): Form[UserFormData] = Form(
mapping(
"firstName" -> nonEmptyText(minLength = 2, maxLength = 30),
"lastName" -> nonEmptyText(minLength = 2, maxLength = 40),
"email" -> email,
"roleAssignmentIds" -> seq(text)
)(UserFormData.apply)(UserFormData.unapply)
)
val roleAssignmentOptions : List[(String, String)] = List("1" -> "Admin", "2" -> "Manager", "3" -> "Service Desk", "4" -> "Jack of All Trades")
Then in your Play Template:
#helper.inputCheckboxGroup(form("roleAssignmentIds"), roleAssignmentOptions)
This will display a list of checkboxes. The IDs ("1".."4") will be sent back back to the server when the checkboxes are checked. (If you fill the form in advance, you need to fill it in with the IDs - "1".."4" - as well.)

spark parse json field and match to different case class

I have some json like below, when I loaded this json some fields is string of json,
How to parse this json using spark scala and look for the key words I am looking for in that json
{"main":"{\"payload\": { \"mode\": [\"Node\"], \"currentSatate\": \"Ready\", \"Previousstate\": \"slow\", \"trigger\": [\"11\", \"12\"], \"AllStates\": [\"Ready\", \"slow\", \"fast\", \"new\"],\"UnusedStates\": [\"slow\", \"new\"],\"Percentage\": \"70\",\"trigger\": [\"11\"]}"}
{"main":"{\"payload\": {\"trigger\": [\"11\", \"22\"],\"mode\": [\"None\"],\"cangeState\": \"Open\"}}"}
{"main":"{\"payload\": { \"trigger\": [\"23\", \"45\"], \"mode\": [\"Edge\"], \"node.postions\": [\"12\", \"23\", \"45\", \"67\"], \"node.names\": [\"aa\", \"bb\", \"cc\", \"dd\"]}}" }
This is how its looking after loading in to data frame
val df = spark.read.json("<pathtojson")
df.show(false)
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|main |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|{"payload": { "mode": ["Node"], "currentSatate": "Ready", "Previousstate": "slow", "trigger": ["11", "12"], "AllStates": ["Ready", "slow", "fast", "new"],"UnusedStates": ["slow", "new"],"Percentage": "70","trigger": ["11"]}|
|{"payload": {"trigger": ["11", "22"],"mode": ["None"],"cangeState": "Open"}} |
|{"payload": { "trigger": ["23", "45"], "mode": ["Edge"], "node.postions": ["12", "23", "45", "67"], "node.names": ["aa", "bb", "cc", "dd"]}} |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Since my json filed is different for all the 3 json strings , is there a way to match define 3 case class and match
I know only matching to one class
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
val parsedJson = mapper.readValue[classname](jsonstring)
is there a way to create a multiple matching case class and match to any particular class ?
You are using Spark SQL, the first thing you have to do is to turn it into a dataset, and then use the spark's methods to deal with them. Don't use Json, all over the place (e.g., like in Play). The first task is to turn it into a dataset.
You could turn the serialize a Json into a case class:
val jsonFilePath: String = "/whatever/data.json"
val myDataSet = sparkSession.read.json(jsonFilePath).as[StudentRecord]
Then here you have the dataset for StudentRecord. So, you can now use the spark's groupBy method to get the data of the column you want from the dataset:
myDataSet.groupBy("whateverTable.whateverColumn").max() //could be min(), count(), etc...
Extra Note: Your Json, should "cleaned up" a little. For example, if it is within your program you can use the multi line way of declaring your Json, and then you don't need to use escape character all over the place:
val myJson: String =
"""
{
}
""".stripMargin
If it is in the file, then the Json you wrote is not correct. So first, make sure you have a syntactically correct Json to work on.

How to iterate over json response array

I have a question about Gatling.
I need to get the following response:
[
{
"id": 1,
"name": "Jack"
},
{
"id": 2,
"name": "John"
}
]
grab those ids, iterate over them and make a new request for each of them.
So far I have this:
.exec(
http("Image list")
.get("/api/img")
.headers(headers_0)
.check(
jsonPath("$..id").findAll.saveAs("imgs")
)
)
It successfuly saves ids to "imgs" which is session variable but I am not able to iterate over them or process it at all. How can I process it? I am new to Gatling and Scala so I have no idea how to approach this. Please help.
You can treat the imgs session variable as a Scala List:
val ids = session("imgs").as[List[Int]]
ids.foreach(id => ...)
An update to reflect the fact that the internal implementation is now a Vector, as OP has discovered:
val ids = session("imgs").as[Seq[Int]]
I found a solution.
The only possible format is Seq. In my case this solves the problem:
val imageIds = session("imgs").as[Seq[String]]

CreateObject with values from JsonFile

I have some Objects Constructor eg:
AM(power: String, speed: String, Height: String, position: PlayerPosition)
Constructor2(motivation: String, description: String, age: Int)
Then I have a JsonFile that holds data needed for all constructors
Is there a way or some library that allows me to parse the contents of the file in a way that allows me to use it for constructing the objets:
eg:
AM(jsonParser.power, jsonParser.speed,jsonParser.Height, jsonParser.position)
I have multiple JsonFiles and the contents are not always the same structure so I was hoping I could use a parser and have access to the data like key: Value pair.
I am quite new to Scala, I know in ruby there are ways that this can be easily achieved and I was hoping this can be done quite easily
So if my file was a json like:
{
"power": "25"
"speed": "65"
"description": "hello"
}
I would be able to data = jsonParse(jsonFile)
then data.speed would equal "25"
I would introduce an intermediate format, that transforms the JSON to a specific case class and map then to the required format.
Every solution depends a bit on the library you use.
I could add an example for play-json if you use this library.