How to return json from Play Scala controller? - json

I would like to know that how can I return json response data from Play(2.2.x) Scala controller class to display on my view page ? I have json objects in Postgresql database(table name: "test" and having: id and name). Please provide me any solutions for it.
I have tried the following cases(a and b), but I am not sure why I am not getting the response(like: names) on my controller, so I can show them on my view page ? since I am very new to Play/Scala and Postgresql.
case a. If I give like:
model:
def getTestValuesFromTable() = {
DB.withConnection { implicit connection =>
val selectJson =SQL("select name from test").on().apply().collect {
case Row(id:Long, Some(name:String)) =>
new TestContent(name)
}
//.head
//JsObject(selectJson().map { row => row[Long]("id").toString -> JsString(row[String]("name")) }.toSeq)
}
}
controller:
def getTest = Action {
val response = TestContent.getTestValuesFromTable()
Ok("Done")
//Ok(response)
}
Output is: Done(application is executing fine without any exceptions, of course json data is not coming since I am returning: Done only, so getting output: "Done")
case b. If I do like this: getting error: not enough arguments for method apply: (n: Int)models.Testname in trait LinearSeqOptimized. Unspecified value parameter n. I really not sure how can I get my response for it ?
controller:
def getTest = Action {
val response = TestContent.getTestValuesFromTable()
// Ok("Done")
Ok(response)
}
model:
def getTestValuesFromTable(): JsValue = {
DB.withConnection { implicit connection =>
val selectJson = SQL("select * from test")
JsObject(selectJson().map { row => row[Long]("id").toString -> JsString(row[String]("name")) }.toSeq)
// val selectJson =SQL("select name from test").on().apply().collect {
// case Row(id:Long, Some(name:String)) =>
// new TestContent(name)
// }
//.head
JsObject(selectJson().map { row => row[Long]("id").toString -> JsString(row[String]("name")) }.toSeq)//not enough arguments for method apply: (n: Int)models.Testname in trait LinearSeqOptimized. Unspecified value parameter n.
}
}
Please let me know how to get my response ?

getJsonValuesFromTable method return nothing (Unit). To fix it change definition of this method to
def getJsonValuesFromTable(testContent: TestContent) = {
or explicitly setting type:
def getJsonValuesFromTable(testContent: TestContent): Unit = {
Also as a next step to let client know that you are returning json, you should set content type:
Ok(Json.obj(response)).as("application/json")

Related

Batch json strings processing using playframework in Scala

I use API which might either return a single json string, a batch of json strings or the string PROCESSING_TIMEOUT, e.g.:
{"id":123,"field1":"test1"}
or:
{"id":123,"field1":"test1"}
{"id":456,"field2":"test2"}
{"id":789,"field3":"test3"}
or (in case of asynchronous processing timeout in remote API)
PROCESSING_TIMEOUT
In the function getRestContent I want to be able to correcty process all these possible outputs, including also the timeout errors. In the current version of the function I lack the possibility to process batch json strings. I think that the best option would be that the function returns List<JsValue> instead of JsValue.
How can I do this modification using Play Framework.
def getRestContent(url:String,param:String,paramValue:String): JsValue = {
var output : JsValue = null
var httpOutput : String = null
try {
val response: HttpResponse[String] = Http(url).timeout(connTimeoutMs = 10000000, readTimeoutMs = 10000000).param(param,paramValue).asString
httpOutput = response.body
} catch
{
case ex: Exception => {
println("Failed connection with remote API")
}
}
if (!httpOutput.contains("PROCESSING_TIMEOUT") && httpOutput != null)
{
try {
output = Json.parse(httpOutput)
}
catch
{
case ex: Exception => {
println("Failed to process a document")
}
}
}
else
{
println("Asynchronous processing timeout")
}
if (output != null)
{
return output
}
else {
return new JsObject(Map("empty" -> JsNumber(0)))
}
}
Disregarding Play Framework your code is not Scala-flavored in general.
Below is a simple example of how better to approach such task in more Scala-way.
Highlights: use scala.util.Try wrapper to normally work with exceptions in a functional way, use pattern matching and monadic map and other methods of collections.
I hope the code below is self-explanatory. I mimicked the API. It returns Strings and not JSON but your 3 basic cases are sufficiently emulated: single line, multiple lines and exceptional case.
Try to run the program few times and you will see that all 3 cases are handled correctly:
import scala.util.{Failure, Success, Try, Random}
/**
* Created by Alex on 3/10/2016.
*/
object Temp {
case class Item(name:String, value:Int)
object API{
def getTimeOutResponse:String = throw new TimeoutException("no luck this time")
def getSingleLineResponse = "{name: \"Alex\", value: 1}"
def getMultiLineResponse = "{name: \"Alex\", value: 1}\n{name: \"HackerDuck\", value: 2}"
def getRandomResponse = (Math.abs(Random.nextInt() % 3)) match{
case 0 => getTimeOutResponse
case 1 => getSingleLineResponse
case 2 => getMultiLineResponse
}
}
def getResults:List[Item]={
Try(API.getRandomResponse) match{
case Success(s) =>{
s.split("\n").toList.map{item =>
val parts = item.split(", ")
Item(parts(0).replace("{name: ", "").replace("\"", ""), parts(1).replace("value: ", "").replace("}", "").toInt)
}
}
case Failure(_) =>{
println("API timeout happened")
List.empty[Item]
}
}
}
def main(args:Array[String])={
println(getResults)
println(getResults)
println(getResults)
}
}
A sample output from my console:
API timeout happened
List()
List(Item(Alex,1))
List(Item(Alex,1), Item(HackerDuck,2))
Process finished with exit code 0
The code becomes less cluttered without all these if statements and !=null and alike. Also you can streamline conversion of your elements sequence to List in one place.

Play 2.4 ActionBuilder / ActionFunction, BodyParsers and JSON

In a Play 2.4 project, I created an Action that do three things.
check that a specific header is present. If not, returns a HTTP error.
use the header value to authenticate the user (a authentication function will be passed to that Action). If the auth fails returns an HTTP error
parse the JSON body to a case class and give it to the Action block code.
To do that, I used the Play Action composition mecanism explain in this page : https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition
but more specifically, the final result I wanted is explained here :
https://www.playframework.com/documentation/2.4.x/ScalaActionsComposition#Putting-it-all-together
I succeeded to write this:
package actions
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.json._
import play.api.mvc.Results._
import play.api.mvc.{WrappedRequest, _}
import scala.concurrent.Future
object Actions {
case class WithApiKeyRequest[A](apiKey: String, request: Request[A]) extends WrappedRequest[A](request)
case class ParsedJsonRequest[A](parsed: Any, request: Request[A]) extends WrappedRequest[A](request)
def AuthenticatedAndParsed[T, A](authencation: String => Future[_])(implicit reader: Reads[T]): ActionBuilder[ParsedJsonRequest] =
WithApiKeyHeaderAction andThen AuthentificationAction(authencation) andThen JsonAction
private[this] def WithApiKeyHeaderAction = new ActionBuilder[WithApiKeyRequest] {
override def invokeBlock[A](request: Request[A], block: (WithApiKeyRequest[A]) => Future[Result]): Future[Result] =
request.headers.get("ApiKey") match {
case Some(apiKey: String) => block(WithApiKeyRequest(apiKey, request))
case _ => Future.successful { BadRequest(Json.obj("errors" -> "ApiKey header needed")) }
}
}
private[this] def AuthentificationAction(authencationFunction: String => Future[_]) = new ActionFilter[WithApiKeyRequest] {
override protected def filter[A](request: WithApiKeyRequest[A]): Future[Option[Result]] =
authencationFunction(request.apiKey)
.map { _ => None } // Do not filter the request
.recover { case _ => Some(Unauthorized) }
}
private[this] def JsonAction[T](implicit reader: Reads[T]) = new ActionBuilder[ParsedJsonRequest] {
composeParser(BodyParsers.parse.json)
override def invokeBlock[A](request: Request[A], block: (ParsedJsonRequest[A]) => Future[Result]): Future[Result] = {
request.body.asInstanceOf[JsValue].validate[T].fold(
errors => Future { BadRequest(Json.obj("errors" -> JsError.toJson(errors))) },
(parsedJson: T) => block(ParsedJsonRequest(parsedJson, request))
)
}
}
}
It seems to work well but it's not perfect because I'm force to use the Any type in the case class ParsedJsonRequest[A](parsed: Any, request: Request[A]) because it seems that I can't do that:
case class ParsedJsonRequest[T, A](parsed: T, request: Request[A])
Is it possible to do that ?
Do you think I can improve my solution ? How ?
My question is not about how to do Action composition. I understand how it works and I succeeded to write my ActionBuilders and my wanted composition.
My question is about how to improve my composition.
Thanks
Jules
Rather than making a new ActionBuilder for a JsonRequest, I would simply use the AuthentificationAction ActionBuilder and pass it a json BodyParser:
AuthentificationAction(parse.json) {
request => // Note that the request has type Request[JsValue]
doStuffWithJson(request.body)
}
Any action using this builder, will get a Request[JsValue] rather than a Request[AnyContent].

Scala - Can I define a function that receives any function as a parameter?

Is it possible, in Scala, to define a function that would receive any other function as a parameter?
It should be something like the following:
object Module extends SecureModule{
val bc = new MyBC()
def method(parameter: Type) = {
exec(bc.method(parameter))
}
def method2(parameter1: Type1, parameter2: Type2) = {
exec(bc.method2(parameter1,parameter2))
}
}
trait SecureModule {
def exec(f: ANY_PARAMETER => ANY_RESULT) = {
//some extra processing
f
}
}
is it possible? If so, how could I achieve this?
Thank you in advance.
The nice thing about scala is that you can create what seems to be your own syntax.
If what you want to do is wrap an operation so that you can do pre and post processing, as well as control the execution context, then you do this by using call-by-name parameters. For example, if we just wanted to time how long a block of code takes, then we could do something like this:
def timer[T](block: => T): (T,Long) = {
val startDate = new Date()
val result = block
val endDate = new Date()
(result, endDate.getTime()-startDate.getTime())
}
We can use it like this:
val (result,duration) = timer {
1+3
}
Or like this
val (result,duration) = timer {
"hello" + " world!"
}
And the result will have the correct type from the block that you pass in while also giving you the duration that you expect.
I am under the impression that your description is somewhat misleading.
The way I understand it, what you (might) want to do is delaying the execution of the bc.method calls until some other code has been performed.
If so, try this:
object Module extends SecureModule{
val bc = new MyBC()
def method(parameter: Type) = {
exec(() => bc.method(parameter))
}
def method2(parameter1: Type1, parameter2: Type2) = {
exec(() => bc.method2(parameter1,parameter2))
}
}
trait SecureModule {
def exec[Result](f: () => Result): Result = {
//some extra processing
f()
}
}
You can't take any function as a parameter. What would you even do it?
At best, you can take any function that has a specific number of parameters.
For example, here, f takes one argument and returns a value.
def exec[A,B](f: A => B)
And here, f takes two arguments:
def exec[A,B,C](f: (A, B) => C)
If you don't care about the return type of the function, you could always use Any instead of a type parameter, since functions are covariant in their return type:
def exec[A](f: A => Any)

Scala, Akka, Spray: How to validate json data before processing?

I can process this json when all the inputs are valid, i.e with valid keys (including case) and values. The next step is to validate keys and return 400 (Bad Request) if the keys or values are invalid. What is a good way to add this validation?
The API call
POST http://localhost:8080/api/v1/adsession
Content-Type: application/json
body {
"sessionId": "abcd123123123",
"serviceGroup": "1234",
"targetCode": {"zipcodes":"30096,30188","code2":"value2"}
}
Route handler
class AdSessionRoutes(services: Services)(implicit ec: ExecutionContext, log: LoggingContext) extends ApiRoute(services) {
implicit val timeout = Timeout(10 seconds)
val postSession = pathPrefix("adsession") & pathEnd & post
val route: Route = {
withService("adSession") { service =>
postSession {
entity(as[AdSession]) { adSession =>
log.info(s"Processing POST ${adSession}")
val future = (service ? CreateAdSession(adSession)).mapTo[AdSession]
onComplete(future) {
case Success(result) =>
complete(StatusCodes.Created, result)
case Failure(e) =>
log.error(s"Error: ${e.toString}")
complete(StatusCodes.InternalServerError, Message(ApiMessages.UnknownException))
}
}
}
}
}
}
Model object
case class AdSession(
sessionId: String,
serviceGroup: String,
targetCodes: Map[String,String],
id: Option[String] = None)
object AdSessionJsonProtocol extends DefaultJsonProtocol {
implicit val adSessionFormat = jsonFormat4(AdSession)
}
entity(as[AdSession]) does map keys to case class fields, but I'm not sure how to catch those errors. I would like to capture those errors as well as add additional validations and return 400 with valid json error response.
I know this may be a little late but since akka-http-2.4.6, you can put the verification logic inside a case class. Check out this for info on how to do it.
Define your own read and write methods for AdSession like this:
object AdSessionJsonProtocol {
implicit object adSessionJsonFormat extends RootJsonFormat[AdSession] {
override def read(json: JsValue): AdSession = ???
override def write(obj: AdSession): JsValue = ???
}
}
Inside read function you can perform additional validation.
Another question is how to pass collected errors to Spray route. I would like to suggest you to wrap AdSession into Either[String, AdSession], for example:
postSession {
entity(as[Either[String, AdSession]]) { adSession =>
So, now your adSessionJsonFormat will looks like:
implicit object adSessionJsonFormat extends RootJsonFormat[Either[String, AdSession]] {
override def read(json: JsValue): Either[String, AdSession] = {
// json.asJsObject.fields access fields, perform checks
// if everything is OK return Right(AdSession(...))
// otherwise return Lift("Error Message")
}
override def write(obj: Either[String, AdSession]): JsValue = ???
}
But, I think it's possible to solve it in more elegant way using some implicit magic.

Having trouble getting Writes to work with Scala Play

To begin with I would like to say sorry for long post, and I really appreciate those who still look into my problem.
I have a controller that should return a json-response with a structure like:
{
result: [
{
key: value,
key: value,
key: value,
key: [
{
key: value,
key: value,
key: value
},...
]
},....
]
}
However I have problems getting the Writes to work as I want.
Note. I will add comments under the line where I have problem.
object APIController extends Controller {
def feed() = Action {
val objects = repo.getObjects().toList
Ok(Json.toJson(Json.obj("result" -> Class_1.apply(objects).result)))
}
first off, if I don't make a Json.obj("result" -> List[objects]) the result key isn't shown in the JSON-result. If I add a Writer for that I get errors saying that the List[objects] must have a Writer. But if I write it like above it doesn't need a Writer for the List[objects]
case class Class_1 (result: Seq[Class_2])
object Class_1 {
def apply(objs: List[Object]) = {
var result:ListBuffer[Class_2] = ListBuffer[Class_2]()
for(obj <- objs) feedResult += Class_2.apply(code)
new Class_1(result.toList)
}
}
*this is where I would put the Writer for Class_1. But if I do this like
implicit val class1Writer = new Writes[Class_1] {
override def writes(o: Class_1): JsValue = Json.obj("result" -> o.result)
} I get the problems I mentioned earlier, that I suddenly need a Writes for a List[objects] of that type*
case class Class_2 (id: Long, id2: Long, listOfStuff: Seq[Class_3])
object Class_2 {
def apply(obj: Object) = {
var items: ListBuffer[Class_3] = ListBuffer[Class_3]()
for(obj1 <- obj.getListOfStuff()) items += Class_3.apply(obj1)
new Class_2(obj.firstID, obj.secID, items.toList)
}
}
implicit val class2Writes = new Writes[Class_2] {
override def writes(o: Class_2): JsValue = {
Json.obj(
"id" -> o.id,
"id2" -> o.id2,
"items" -> o.listOfStuff
)
}
}
*the "items" -> o.listOfStuff says it needs a Writes for a List[types in the list] but I have a Writes for the objects in the list (Class_3) and I don't need a Writes for when serializing a list of objects from Class_2, why is it behaving like this?*
case class Class_3 (id: Long, text: String)
object Class_3 {
def apply(obj: Object) = {
new Class_3(obj.id, obj.funnyText)
}
}
implicit val class3Writer = new Writes[Class_3] {
override def writes(o: Class_3): JsValue = {
Json.obj(
"id" -> o.id,
"text" -> o.text
)
}
}
}
The error I get from this code is:
No Json deserializer found for type Seq[Class_3]. Try to implement an implicit Writes or Format for this type.
[error] "items" -> o.listOfStuff
[error] ^
If I remove this line in the Writes it compiles and works.
And I think that's weird since the first list I serialize doesn't have a Writer, only for the objects in the list.
Does anyone know why it behaves like this?
What should I do to accomplish what I'm after? (I hope you see what I'm trying to do)
Thanks in advance.
Just put the implicit val class3Writer ahead of class2Writes