Parsing scala Json into dataframe - scala

Sample Json
"alternateId": [
{
"type": "POPID",
"value": "1-7842-0759-001"
},
{
"type": "CAMID",
"value": "CAMID 0000-0002-7EC1-02FF-O-0000-0000-2"
},
{
"type": "ProgrammeUuid",
"value": "1ddb01e2-6146-4e10-bba9-dde40d0ad886"
}
]
I want to update a existing dataframe with two columns, those two columns are POPID and CAMID . These two values needs to be parsed from json structure
I dont know how to parse this structure , Can you help me on what do i need to change on fetchField method. As per above json POPID is placed first and CAMID is placed second, but in real jsons, it can be placed at one of those 3 places inside alternateId.
val fetchCAMID_udf = udf(fetchCAMID _)
val fetchPOPID_udf = udf(fetchPOPID _)
var updatedDf = //Data frame initialize
updatedDf = updatedDf.withColumn("CAMID", fetchCAMID_udf(col("alternate_id")))
updatedDf = updatedDf.withColumn("POPID", fetchPOPID_udf(col("alternate_id")))
updatedDf .show(10,false)
def fetchCAMID(jsonStr: String): String = {
var CAMID: String = fetchField(jsonStr, "CAMID")
CAMID
}
def fetchPOPID(jsonStr: String): String = {
fetchField(jsonStr, "POPID")
}
def fetchField(jsonStr: String, fieldName: String): String = {
try {
implicit val formats = DefaultFormats
val extractedField = jsonStr match {
case "(unknown)" => jsonStr
case _ => {
val json = JsonMethods.parse(jsonStr)
val resultExtracted = (json \\ fieldName)
val result = resultExtracted match {
case _: JString => resultExtracted.extract[String]
case _: JInt => resultExtracted.extract[Int].toString
case _: JObject => "(unknown)"
}
result
}
}
extractedField
}
catch{
case e: Exception =>{
log.error(s"Fetch field failed. Field name: $fieldName . Json: $jsonStr")
"(unknown)"
}
}
}

Change your fetchField function as the following
def fetchField(jsonStr: String, fieldName: String): String = {
try {
val typeAndValue = (JsonMethods.parse("{"+jsonStr+"}") \ "alternateId" \ "type" \\ classOf[JString]).zip(JsonMethods.parse("{"+jsonStr+"}") \ "alternateId" \ "value" \\ classOf[JString])
typeAndValue.filter(_._1 == fieldName).map(_._2).toList(0)
}catch{
case e: Exception =>{
"(unknown)"
}
}
}
and you get the CAMID and POPID populated

you can read the JSON using Spark and get it using regular spark operations
val df=spark.read.option("multiLine",true).json("test.json")
df.select($"alternateId".getItem(0).as("pop"),$"alternateId".getItem(1).as("cam")).select($"pop.value".as("POPID"),$"cam.value".as("CAMID")).show()
+---------------+--------------------+
| POPID| CAMID|
+---------------+--------------------+
|1-7842-0759-001|CAMID 0000-0002-7...|
+---------------+--------------------+

Related

How to deserialize Kafka Avro messages using POJOs with Spark Structured Streaming

I'm using Spark Structured Streaming with Kafka integration in order to read Avro messages in order to deserialized them. The goal is to read these messages using a generated POJO as a schema. The code I'm using is the following :
val kafkaConsumerDf: DataFrame = sparkSession
.readStream
.format("kafka")
.option("subscribe", inputTopic)
.option("group.id", queryName)
.option("startingOffsets", "earliest")
.option("kafka.bootstrap.servers", bootstrapServers)
.load()
kafkaConsumerDf
.writeStream
.queryName(queryName)
.option("checkpointLocation", checkpointPath)
.foreachBatch((batchDF: DataFrame, batchId: Long) => {
val deserializedDf: DataFrame = batchDF.select(
from_avro(col("value"), schemaRegistryConfig) as "value"
).select("value.*")
}).start()
The schema of the data is as follows:
{
"fields": [
{
"name": "idA",
"type": "string"
},
{
"name": "idB",
"type": "string"
},
{
"name": "idC",
"type": "string"
},
{
"name": "name",
"type": [
"string",
"null"
]
}
],
"name": "Avro",
"namespace": "com.test.avro",
"type": "record"
}
As I stated above, I will want to use a POJO (Avro) as a schema to read the consumed data into Kafka. The POJO that represents the data structure is:
/** MACHINE-GENERATED FROM AVRO SCHEMA. DO NOT EDIT DIRECTLY */
import scala.annotation.switch
final case class Avro(var idA: String, var idB: String, var idC: String, var name: Option[String]) extends org.apache.avro.specific.SpecificRecordBase {
def this() = this("", "", "", "", None, None, None, None)
def get(field$: Int): AnyRef = {
(field$: #switch) match {
case 0 => {
idA
}.asInstanceOf[AnyRef]
case 1 => {
idB
}.asInstanceOf[AnyRef]
case 2 => {
idC
}.asInstanceOf[AnyRef]
case 3 => {
name match {
case Some(x) => x
case None => null
}
}.asInstanceOf[AnyRef]
case _ => new org.apache.avro.AvroRuntimeException("Bad index")
}
}
def put(field$: Int, value: Any): Unit = {
(field$: #switch) match {
case 0 => this.idA = {
value.toString
}.asInstanceOf[String]
case 1 => this.idB = {
value.toString
}.asInstanceOf[String]
case 2 => this.idC = {
value.toString
}.asInstanceOf[String]
case 4 => this.name = {
value match {
case null => None
case _ => Some(value.toString)
}
}.asInstanceOf[Option[String]]
case _ => new org.apache.avro.AvroRuntimeException("Bad index")
}
()
}
def getSchema: org.apache.avro.Schema = Avro.SCHEMA$
}
object Equipement {
val SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Avro\",\"namespace\":\"com.test.avro\",\"fields\":[{\"name\":\"idA\",\"type\":\"string\"},{\"name\":\"idB\",\"type\":\"string\"},{\"name\":\"idC\",\"type\":\"string\"},{\"name\":\"name\",\"type\":[\"string\",\"null\"]}]}")
}
So, instead of using the from_avro() function and the schema registry, is it possible to use its POJO in order to deserialize the data? For example:
val deserializedDf = batchDF.
...
...
.as[Avro]
Do you have any ideas?

json parsing using circe in scala

I'm trying to make use of circe for json parsing in scala. Can you please help me parse 'pocs' from the data in the case class as well? here is the code:
import io.circe.Decoder
import io.circe.generic.semiauto.deriveDecoder
import io.circe.parser
val json: String =
"""
{
"segmements": [
{
"tableName": "X",
"segmentName": "XX",
"pocs": [
"aa#aa.com",
"bb#bb.com"
]
},
{
"tableName": "Y",
"segmentName": "YY",
"pocs": [
"aa#aa.com",
"bb#bb.com"
]
}
]
}
"""
final case class TableInfo(tableName: String, segmentName: String)
object TableInfo {
implicit final val TableInfoDecoder: Decoder[TableInfo] = deriveDecoder
}
val result = for {
data <- parser.parse(json)
obj <- data.asObject.toRight(left = new Exception("Data was not an object"))
segmements <- obj("segmements").toRight(left = new Exception("Json didn't had the
segments key"))
r <- segmements.as[List[TableInfo]]
} yield r
println(result)
scastie link: https://scastie.scala-lang.org/BalmungSan/eVEvBulOQwGzg5hIJroAoQ/3
Just add parameter typed as collection of String:
final case class TableInfo(tableName: String, segmentName: String, pocs: Seq[String])
scastie

Play Framework Strange Behavior when Parsing JSON Body

I have a endpoint that takes in a JSON body. I have implicit reads and writes for this JSON format. In the endpoint, I do a validation of the JSON and fold on the result! Here it is:
def updatePowerPlant(id: Int) = Action.async(parse.tolerantJson) { request =>
request.body.validate[PowerPlantConfig].fold(
errors => {
Future.successful(
BadRequest(
Json.obj("message" -> s"invalid PowerPlantConfig ${errors.mkString(",")}")
).enableCors
)
},
success => {
dbService.insertOrUpdatePowerPlant(success).runAsync.materialize.map {
case Failure(ex) =>
InternalServerError(s"Error updating PowerPlant " +
s"Reason => ${ex.getMessage}").enableCors
case Success(result) =>
result match {
case Left(errorMessage) =>
BadRequest(Json.obj("message" -> s"invalid PowerPlantConfig $errorMessage")).enableCors
case Right(updatedConfig) =>
Ok(Json.prettyPrint(Json.toJson(updatedConfig))).enableCors
}
}
}
)
}
So as it can be seen that I fold on the error and I return a BadRequest. But when I tried writing a unit test, I do not get the HTTP status as BadRequest as I expect, but the test crashes with an exception as below:
JsResultException(errors:List((,List(ValidationError(List(error.expected.jsnumber),WrappedArray())))))
play.api.libs.json.JsResultException: JsResultException(errors:List((,List(ValidationError(List(error.expected.jsnumber),WrappedArray())))))
at play.api.libs.json.JsReadable$$anonfun$2.apply(JsReadable.scala:23)
at play.api.libs.json.JsReadable$$anonfun$2.apply(JsReadable.scala:23)
at play.api.libs.json.JsResult$class.fold(JsResult.scala:73)
at play.api.libs.json.JsError.fold(JsResult.scala:13)
at play.api.libs.json.JsReadable$class.as(JsReadable.scala:21)
at play.api.libs.json.JsDefined.as(JsLookup.scala:132)
at com.inland24.plantsim.models.package$$anon$1.reads(package.scala:61)
at play.api.libs.json.JsValue$class.validate(JsValue.scala:18)
at play.api.libs.json.JsObject.validate(JsValue.scala:76)
at com.inland24.plantsim.controllers.PowerPlantController$$anonfun$updatePowerPlant1$1.apply(PowerPlantController.scala:64)
at com.inland24.plantsim.controllers.PowerPlantController$$anonfun$updatePowerPlant1$1.apply(PowerPlantController.scala:63)
at play.api.mvc.Action$.invokeBlock(Action.scala:498)
at play.api.mvc.Action$.invokeBlock(Action.scala:495)
at play.api.mvc.ActionBuilder$$anon$2.apply(Action.scala:458)
at com.inland24.plantsim.controllers.PowerPlantControllerTest$$anonfun$4$$anonfun$apply$mcV$sp$11.apply(PowerPlantControllerTest.scala:313)
at com.inland24.plantsim.controllers.PowerPlantControllerTest$$anonfun$4$$anonfun$apply$mcV$sp$11.apply(PowerPlantControllerTest.scala:296)
at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.WordSpecLike$$anon$1.apply(WordSpecLike.scala:1078)
at org.scalatest.TestSuite$class.withFixture(TestSuite.scala:196)
at com.inland24.plantsim.controllers.PowerPlantControllerTest.withFixture(PowerPlantControllerTest.scala:40)
at org.scalatest.WordSpecLike$class.invokeWithFixture$1(WordSpecLike.scala:1075)
at org.scalatest.WordSpecLike$$anonfun$runTest$1.apply(WordSpecLike.scala:1088)
at org.scalatest.WordSpecLike$$anonfun$runTest$1.apply(WordSpecLike.scala:1088)
at org.scalatest.SuperEngine.runTestImpl(Engine.scala:289)
at org.scalatest.WordSpecLike$class.runTest(WordSpecLike.scala:1088)
at com.inland24.plantsim.controllers.PowerPlantControllerTest.runTest(PowerPlantControllerTest.scala:40)
at org.scalatest.WordSpecLike$$anonfun$runTests$1.apply(WordSpecLike.scala:1147)
at org.scalatest.WordSpecLike$$anonfun$runTests$1.apply(WordSpecLike.scala:1147)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:396)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:373)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:410)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:379)
at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:461)
at org.scalatest.WordSpecLike$class.runTests(WordSpecLike.scala:1147)
at com.inland24.plantsim.controllers.PowerPlantControllerTest.runTests(PowerPlantControllerTest.scala:40)
at org.scalatest.Suite$class.run(Suite.scala:1147)
at com.inland24.plantsim.controllers.PowerPlantControllerTest.org$scalatest$WordSpecLike$$super$run(PowerPlantControllerTest.scala:40)
at org.scalatest.WordSpecLike$$anonfun$run$1.apply(WordSpecLike.scala:1192)
at org.scalatest.WordSpecLike$$anonfun$run$1.apply(WordSpecLike.scala:1192)
at org.scalatest.SuperEngine.runImpl(Engine.scala:521)
at org.scalatest.WordSpecLike$class.run(WordSpecLike.scala:1192)
at com.inland24.plantsim.controllers.PowerPlantControllerTest.org$scalatest$BeforeAndAfterAll$$super$run(PowerPlantControllerTest.scala:40)
at org.scalatest.BeforeAndAfterAll$class.liftedTree1$1(BeforeAndAfterAll.scala:213)
at org.scalatest.BeforeAndAfterAll$class.run(BeforeAndAfterAll.scala:210)
at com.inland24.plantsim.controllers.PowerPlantControllerTest.run(PowerPlantControllerTest.scala:40)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45)
at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$1.apply(Runner.scala:1340)
at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$1.apply(Runner.scala:1334)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1334)
at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1011)
at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1010)
at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1500)
at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:1010)
at org.scalatest.tools.Runner$.run(Runner.scala:850)
at org.scalatest.tools.Runner.run(Runner.scala)
at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.runScalaTest2(ScalaTestRunner.java:138)
at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.main(ScalaTestRunner.java:28)
Here is my unit test:
"not update for an invalid PowerPlantConfig JSON" in {
// We are updating the PowerPlant with id = 101, Notice that the powerPlantId is invalid
val jsBody =
"""
|{
| "powerPlantId":"invalidId",
| "powerPlantName":"joesan 1",
| "minPower":100,
| "maxPower":800,
| "rampPowerRate":20.0,
| "rampRateInSeconds":"2 seconds",
| "powerPlantType":"RampUpType"
|}
""".stripMargin
val result: Future[Result] =
controller.updatePowerPlant(101)
.apply(
FakeRequest().withBody(Json.parse(jsBody))
)
result.materialize.map {
case Success(succ) =>
assert(succ.header.status === BAD_REQUEST)
case Failure(_) =>
fail("Unexpected test failure when Updating a PowerPlant! Please Analyze!")
}
}
Any idea why I'm not getting the expected behavior? I'm expecting that I get a HTTP BadRequest back!
EDIT: To get rid of the unexpected exception, I had to wrap my code into a Try block and I do not want that. So this piece of code gets rid of the error:
def updatePowerPlant(id: Int) = Action.async(parse.tolerantJson) { request =>
scala.util.Try(request.body.validate[PowerPlantConfig]) match {
case Failure(fail) =>
Future.successful(InternalServerError(s"Error updating PowerPlant " +
s"Reason => ${fail.getMessage}").enableCors)
case Success(succ) =>
succ.fold(
errors => {
Future.successful(
BadRequest(
Json.obj("message" -> s"invalid PowerPlantConfig ${errors.mkString(",")}")
).enableCors
)
},
success => {
dbService.insertOrUpdatePowerPlant(success).runAsync.materialize.map {
case Failure(ex) =>
InternalServerError(s"Error updating PowerPlant " +
s"Reason => ${ex.getMessage}").enableCors
case Success(result) =>
result match {
case Left(errorMessage) =>
BadRequest(Json.obj("message" -> s"invalid PowerPlantConfig $errorMessage")).enableCors
case Right(updatedConfig) =>
Ok(Json.prettyPrint(Json.toJson(updatedConfig))).enableCors
}
}
}
)
}
}
But as it can be seen that there is this additional Try(....) block and I do not want this!
Here is my definition of PowerPlantConfig:
sealed trait PowerPlantConfig {
def id: Int
def name: String
def minPower: Double
def maxPower: Double
def powerPlantType: PowerPlantType
}
object PowerPlantConfig {
case class OnOffTypeConfig(
id: Int,
name: String,
minPower: Double,
maxPower: Double,
powerPlantType: PowerPlantType
) extends PowerPlantConfig
case class RampUpTypeConfig(
id: Int,
name: String,
minPower: Double,
maxPower: Double,
rampPowerRate: Double,
rampRateInSeconds: FiniteDuration,
powerPlantType: PowerPlantType
) extends PowerPlantConfig
case class UnknownConfig(
id: Int = -1,
name: String,
minPower: Double,
maxPower: Double,
powerPlantType: PowerPlantType
) extends PowerPlantConfig
// represents all the PowerPlant's from the database
case class PowerPlantsConfig(
snapshotDateTime: DateTime,
powerPlantConfigSeq: Seq[PowerPlantConfig]
)
}
Here is my JSON reads and writes:
implicit val powerPlantCfgFormat: Format[PowerPlantConfig] = new Format[PowerPlantConfig] {
def reads(json: JsValue): JsResult[PowerPlantConfig] = {
val powerPlantTyp = PowerPlantType.fromString((json \ "powerPlantType").as[String])
powerPlantTyp match {
case PowerPlantType.OnOffType =>
JsSuccess(OnOffTypeConfig(
id = (json \ "powerPlantId").as[Int],
name = (json \ "powerPlantName").as[String],
minPower = (json \ "minPower").as[Double],
maxPower = (json \ "maxPower").as[Double],
powerPlantType = powerPlantTyp
))
case PowerPlantType.RampUpType =>
JsSuccess(RampUpTypeConfig(
id = (json \ "powerPlantId").as[Int],
name = (json \ "powerPlantName").as[String],
minPower = (json \ "minPower").as[Double],
rampPowerRate = (json \ "rampPowerRate").as[Double],
rampRateInSeconds = Duration.apply((json \ "rampRateInSeconds").as[String]).asInstanceOf[FiniteDuration],
maxPower = (json \ "maxPower").as[Double],
powerPlantType = powerPlantTyp
))
case _ =>
JsSuccess(UnknownConfig(
id = (json \ "powerPlantId").as[Int],
name = (json \ "powerPlantName").as[String],
minPower = (json \ "minPower").as[Double],
maxPower = (json \ "maxPower").as[Double],
powerPlantType = powerPlantTyp
))
}
}
def writes(o: PowerPlantConfig): JsValue = {
if (o.powerPlantType == RampUpType) {
Json.obj(
"powerPlantId" -> o.id,
"powerPlantName" -> o.name,
"minPower" -> o.minPower,
"maxPower" -> o.maxPower,
"rampPowerRate" -> o.asInstanceOf[RampUpTypeConfig].rampPowerRate,
"rampRateInSeconds" -> o.asInstanceOf[RampUpTypeConfig].rampRateInSeconds.toString(),
"powerPlantType" -> PowerPlantType.toString(o.powerPlantType)
)
}
else {
Json.obj(
"powerPlantId" -> o.id,
"powerPlantName" -> o.name,
"minPower" -> o.minPower,
"maxPower" -> o.maxPower,
"powerPlantType" -> PowerPlantType.toString(o.powerPlantType)
)
}
}
}
According your stacktrace (line I marked)
JsResultException(errors:List((,List(ValidationError(List(error.expected.jsnumber),WrappedArray())))))
play.api.libs.json.JsResultException: JsResultException(errors:List((,List(ValidationError(List(error.expected.jsnumber),WrappedArray())))))
at play.api.libs.json.JsReadable$$anonfun$2.apply(JsReadable.scala:23)
at play.api.libs.json.JsReadable$$anonfun$2.apply(JsReadable.scala:23)
at play.api.libs.json.JsResult$class.fold(JsResult.scala:73)
at play.api.libs.json.JsError.fold(JsResult.scala:13)
--> at play.api.libs.json.JsReadable$class.as(JsReadable.scala:21)
at play.api.libs.json.JsDefined.as(JsLookup.scala:132)
at com.inland24.plantsim.models.package$$anon$1.reads(package.scala:61)
at play.api.libs.json.JsValue$class.validate(JsValue.scala:18)
at play.api.libs.json.JsObject.validate(JsValue.scala:76)
at com.inland24.plantsim.controllers.PowerPlantController$$anonfun$updatePowerPlant1$1.apply(PowerPlantController.scala:64)
at com.inland24.plantsim.controllers.PowerPlantController$$anonfun$updatePowerPlant1$1.apply(PowerPlantController.scala:63)
you used as[Int] in your Read format for id field for PowerPlantConfig.
When you call as[Int], you are trying to force the given json path to type Int. It throws an exception if it cannot (as in your test). You can read on difference betweem as, asOpt and validate here for example
Update
If you look into implementation of as, asOpt and validate you will see that all these three do at first the same thing, but than differs in a way:
validate - I do need result either result or info on failure wrapped (just call reads of implicit arg on json)
asOpt - I need either result or none, if reads under used for resolution return parse error it is ignored as not set at all
as - I need either result, or exception. In other words "I'm sure, that this is always such type, if not, than it is general error"
Both as and asOpt are "extended validate" with interpreting result.
Example
Example how to move from as to validate in hierarchy (two Formats - one as yours with as which will throw exception, and another with validate which will not throw exception):
sealed trait PowerPlantConfig {
def id: Int
}
case class RampUpTypeConfig(id: Int) extends PowerPlantConfig
implicit val powerPlantCfgFormat: Format[PowerPlantConfig] = new Format[PowerPlantConfig] {
def reads(json: JsValue): JsResult[PowerPlantConfig] = {
JsSuccess(RampUpTypeConfig(
id = (json \ "powerPlantId").as[Int]
))
}
def writes(o: PowerPlantConfig): JsValue = {
Json.obj(
"powerPlantId" -> o.id)
}
}
val powerPlantCfgFormatFixed: Format[PowerPlantConfig] = new Format[PowerPlantConfig] {
def reads(json: JsValue): JsResult[PowerPlantConfig] = {
for {
id <- (json \ "powerPlantId").validate[Int]
} yield {
RampUpTypeConfig(
id = id
)
}
}
def writes(o: PowerPlantConfig): JsValue = {
Json.obj(
"id" -> o.id)
}
}
Json.parse("""{"powerPlantId":"123"}""").validate[PowerPlantConfig](powerPlantCfgFormatFixed)
And output will be not an exception but JsFailure as expected
res1: play.api.libs.json.JsResult[PowerPlantConfig] = JsError(List((,List(ValidationError(error.expected.jsnumber,WrappedArray())))))

Gatling> Json response map with Json File

Hi I want to validate my Json File saved in resources with the Json response via Get method.
My Saved Json File looks like this, which is in an array
[{
"id":"123"
}]
I am unable to map the File with Response.
object Products {
val jsonFetchProductIDs = ElFileBody("abc.json")
val fetchProductIds: HttpRequestBuilder = http("fetch")
.get("endpoint")
.body(jsonFetch)
val products = http("Products")
.get("endpoint")
}
class ProductsTest extends Simulation {
val productIdInfo = exec(
Products.products
.check(status.is(200), jsonPath("$.id").ofType[Map[String,Any]].findAll.saveAs("productsID"))
)
val productIdResult = exec(session => {
val id = session.get("id").asOption[String]
foreach("${productsID}", "id") {
exec(session => {
val idMap = session("id").as[Map[String, Any]]
val allId = idMap(" allId")
session.set("allId", allId)
})
}
session
})
val getproductidscenario1 = scenario("Products ID")
.exec(Login.login)
.exec(EventBus.openSSE)
.exec(Accounts.fetchInitialAccounts)
.pause(10)
.exec(productIdInfo)
.exec(productIdResult)
setUp (
getproductidscenario1.inject(atOnceUsers(1)).protocols(HttpConf.httpConf)
)
}
You can use the command below to compare the result against file content
bodyString.is(ElFileBody("expected_response.json"))

change data type sequence String to String

my DAL :
def login(username: String,pass :String) =
sql"""SELECT AD1SYS.PKG_STC_LOGIN.USER_LOGIN ('#$username','#$pass')FROM DUAL""".as[String]
def getEmpName(username: String,empName :String) =
sql"""SELECT AD1SYS.PKG_STC_LOGIN.GET_EMPL_NAME ('#$username','#$empName') FROM DUAL""".as[(String)]
my service :
def login(username:String,pass:String): Future[Seq[(String)]] = {
db.run(DalLogin.login(username, pass))
}
def getEmpName(username:String,empName:String): Future[Seq[(String)]] = {
db.run(DalLogin.getEmpName(username, empName))
}
My Controller :
def login = Action.async(BodyParsers.parse.json) { request =>
val username = (request.body \ "username").as[String]
val pass = (request.body \ "pass").as[String]
ServiceLogin.login(username, pass).map { data =>
ServiceLogin.getEmpName(username,data).map(result =>
Ok(Json.toJson(result.map( p =>
ModelKodeCabang(p)
))
))}
}
the result from Service.login is Seq(String) "data", i can't use the Seq(String) for parameter ServiceLogin.getEmpName(username,data).. how to convert Seq(String) to String ??