Play 2.3 - Changing to WebSocket.tryAccept from async - scala

I'm new rather new to Scala so I think this might be a very small problem.
I'm currently trying to change the method chat from using the deprecated WebSocket.async to WebSocket.tryAccept. The application uses the sample chat found at PlayFramework websocket-chat
I'm having trouble creating the complex Future type that the method requires.
This is the old method:
def chat() = WebSocket.async[JsValue] {
request =>
ChatRoom.join("User: 1")
}
New method:
def chat2() = WebSocket.tryAccept[JsValue] {
request =>
try {
// ChatRoom.join returns (iteratee,enumerator)
ChatRoom.join("User: 1").map(e => Right(e))
} catch {
case e: Exception =>
Left(Ok("Failed")) // Error here
}
}
My error message:
found : Left[Result,Nothing]
required: Future[Either[Result,(Iteratee[JsValue, _], Enumerator[JsValue])]]
I have no idea how I am supposed to create such a complex result for such a simple message.
Although ChatRoom.join("User: 1").map(e => Right(e)) doesn't show any errors now, I'm unsure if this is the correct implementation.

I'm not in front of an IDE at the moment, so I can't answer fully, but the return type it's asking for isn't as complex as it seems. An "Either" is a "Left" or a "Right" in the same way that an "Option" is a "Some" or a "None". So what it's asking for is a Future (which Websocket.async should also have required) that contains either a Left[Result] -- the fail-to-connect case, or a Right[(Iteratee, Enumerator)] -- the success case. Assuming that Chatroom.join returns a Future[(Iteratee, Enumerator)], the map operation is simply wrapping that in a "Right". The first thing I'd try is wrapping Left(Ok("Failed")) in a Future and see what happens.

Related

How to complete Akka Http response with Stream and Custom Status Code

I've got an akka-http application that uses akka-streams for data processing. So, it makes some sense to complete the request with Source[Result, _] to get backpressure across HTTP boundary for free.
Versions:
akka-http 10.0.7
akka-streams 2.5.2
akka 2.5.2
This is the simplified version of the code, and it works just fine.
pathEnd { post { entity(asSourceOf[Request]) { _ =>
complete {
Source.single("ok")
}
}}}
Since this enpoint is supposed to create and entity, instead of returning 200 OK to the requester I'd like to return 204 CREATED status code. However, I wasn't able to find a way to do that:
complete { Created -> source.single("ok") } fails compilation with Type mismatch, expected: ToResponseMarshallable, actual: (StatusCodes.Success, Source[String, NotUsed])
complete { source.single((Created, "ok")) } fails with Type mismatch, expected: ToResponseMarshallable, actual: Source[(StatusCodes.Success, String), NotUsed]
complete(Created) { Source.single("ok") } fails with Type mismatch, expected: RequestContext, actual: Source[String,NotUsed]
complete(Created, Source.signle("ok") fails with too many arguments for method complete(m: => ToResponseMarshallable)
It looks like custom marshaller might be a way to achieve that, but it'll basically mean I'll need one unmarshaller per endpoint, which isn't quite convenient or clear.
So, the question is, are there a (more convenient than custom unmarshaller) way to complete the request with Source[_,_] while also providing status code.
From the documentation:
complete(Created -> "bar")
If you want to provide some Source of data then construct the HttpResponse and pass it to complete:
import akka.http.scaladsl.model.HttpEntity.Chunked
import akka.http.scaladsl.model.ContentTypes
import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart
complete {
val entity =
Chunked(ContentTypes.`text/plain(UTF-8)`,
Source.single("ok").map(ChunkStreamPart.apply))
HttpResponse(status = Created, entity=entity)
}
I hit this problem and took the approach of using mapResponse to override the status code. This is the simplest approach I've found.
mapResponse(_.copy(status = StatusCodes.Accepted)) {
complete {
Source.single("ok")
}
}
The drawback of Ramon's answer is that you become responsible for both marshalling the stream (to a ByteString), and for the content negotiation.

parse.form method defined in play framework 2.2.x?

Play documentation mentions parse.form method which can be used to bind to an incoming request. I am using play 2.2.x. Is this method defined in this release? I am getting compilation error
value form is not a member of object controllers.Application.parse
def regSubmit = Action(parse.form(userForm) { implicit request =>
val userData= request.body
Ok(views.html.regconf("Registration Successful")(userForm.fill(userData)))
})
As far as I can tell from the 2.2.x source code, parse.form did not exist then, and was only introduced in 2.4.x.
Any reason not to use the "equivalent" bindFromRequest and deal with errors that might be present? Along the lines of:
def regSubmit = Action { implicit request =>
userForm.bindFromRequest.fold (
errors => //-- 'errors' is a form with FormErrors set
Ok(views.html.register(errors)) //-- register is the initial form
userData => //-- 'userData' is the case class that userForm maps to
Ok(views.html.regconf("Registration Successful")(userForm.fill(userData)))
)
}
I have not checked the source code to see whether it is in 2.2.x. It is not mentioned on the ScalaForms page of the docs.

Working with futures in slick and scalatra

I am trying to handle a future I got from slick in order to generate a response to a request, but I'm stuck at the "async" part.
Here is a snippet:
get("/tmp") {
new AsyncResult() {
override val is: Future[_] = db.run(Users.findUserWithLogin("user"))
}
}
Now, the db.run call returns a Future[Option[User]]. How do I returns a response depending on the content of the option?
In this case, you need to map the future returned by Slick to the result that you want rather than setting is directly to the Slick result. So, the following would be an example of how you might handle it:
get("/tmp") {
new AsyncResult() {
val is = db.run(Users.findUserWithLogin("user")) map {
case Some(u) => //return some stuff about the user
case None => //return some stuff about user not being found
}
}
}
As noted in the comments below, the AsyncResult is not strictly necessary. You can find more details in the Scalatra documentation.

Capture a return value for logging and then return the value in Scala

What is the most 'scala-ic' way to capture a value (possibly one that is not idempotent) for logging and returning the same value.
I can think of 'return' statement the only way to do it, but apparently using 'return' should be avoided in scala .
Use case:
def myfunc(argument) : ReturnType{
val response:ReturnType = dependency()
// dependency() is not idemptotent
// so calling more than once will have side-effects
logger.debug(response.member1 , response.member2)
return response
}
Is there a way to achieve this without using a 'return' keyword.
I am a newbie to scala so some (or most) of what I said could be wrong, and would be happy to be corrected.
Just reifying #Shadowlands answer.
def myfunc(argument: ArgType): ReturnType {
val response = dependency()
logger.debug(response.member1, response.member2)
response
}

Composing `Future` result in Play Framework with Scala

I am trying to write a Play Framework asynchronous Action for the following URL:
POST /users/:userId/items
My database calls all return Future[...], where ... is Option[A] for find methods and Option[Id] for create methods.
I would like to check for the existence of the userId before trying to create the new item. I have a method Users.findById(userId) that returns a Future[Option[User]]. The result is Some(User) if the user exists and None if not. Items.create() also returns a Future[Option[itemId]].
I am trying to compose something using for:
for {
user <- Users.findById(userId)
if user.isDefined
} yield {
Items.create(...) map { itemId => Ok(itemId) } getOrElse NotFound
}
I would like to return Ok(itemId) if the item is successfully created. I'm not sure how to handle the error case. I would like to return NotFound if either the userId is invalid or the item cannot be created (maybe a field conflicts with a unique value already in the database).
I'm not sure what to put after the for structure. I tried getOrElse, but that does not compile, since Future does not have a getOrElse method.
Ideally, I can handle URLs containing several ids to check, e.g.:
PUT /users/:userId/foo/:fooId/bar/:barId
and confirm that userId, fooId, and barId are all valid before doing the update. All of those calls (Users.findById, Foo.findById, and Bar.findById) will return Future[Option[A]].
It's that double-nesting (Future of Option) that seems to get people every time. Things become a lot easier if you can flatten stuff out first.
In this case, Future already has a way of representing an error condition, it can wrap an Exception as well as a success value, that's something you can use...
// making this a Singleton avoids the cost of building a stack trace,
// which only happens when an Exception is constructed (not when it's thrown)
object NotFoundException extends RuntimeException("Empty Option")
// The map operation will trap any thrown exception and fail the Future
def squish[T](x: Future[Option[T]]) =
x map { _.getOrElse(throw NotFoundException) }
It's now a lot easier to use those squished results in a comprehension:
val result = for {
user <- squish(Users findById userId)
itemId <- squish(Items.create(user, ...))
} yield {
Ok(itemId)
} recover {
case NotFoundException => NotFound
}
Which will, of course, evaluate to a Future. This is async programming, after all :)
Any exceptions other than NotFoundException will still be exposed.