I am playing around with WebSockets in PlayFramework 2.2. I would like to do some checks on the initial request and possibly return an appropriate HTTP status. In principle it would look like something like this, asked in this question:
def ws(username: String) = {
if (username == "asoliman")
Action { request =>
Forbidden("Soliman is not allowed here")
}
else
WebSocket.using[String] { request =>
val in = Iteratee.foreach[String]( s => println("got: " + s)).mapDone(_ => println("Disconnected"))
val out = Enumerator[String]("Ahmed", "Mohamed", "Ibrahim").andThen(Enumerator.enumInput(Input.EOF))
(in, out)
}
}
As noted, this is not possible as the WebSocket's using and async need to return a Tuple2[Iteratee, Enumerator].
Is there a recommended approach to this?
Or, is there a way to send Websocket's Status Codes?
UPDATE 7 October 2015:
In newer PlayFramework versions, it is possible to reject a connection and therefore return, say, a Forbidden status. Check the documentation here: https://www.playframework.com/documentation/2.4.x/ScalaWebSockets
ORIGINAL ANSWER:
Answer is, it is not possible at the moment with PlayFramework 2.2. Regular HTTP statuses are not viable as the response needs to be a WebSocket (via using/async), and WebSocket statuses are not implemented. I filed an issue about it in their repo, we need to wait for future releases - or contribute to make it happen :-)
Related
I am using SOAP UI 5.7.0 to mock a REST service and it is working fine. Only, when I want to access the body of a POST request with mockRequest.requestContent, the correct content is returned only in the first call, but from then on, it always returns the empty string.
I tried the call in OnRequestScript and in the POST requests own Dispatch script but the behavior is the same in both cases. I have the suspicion, that the Stream of the request is already read somewhere else and so does not return any more content. But I don't know what to do about it.
I wonder what is the correct way to read the content of a POST request.
Thank you
Appears to be a known issue, see posts in the community forum here and here.
this seems to be an old bug of PUT operation in REST mocks.
Unfortunately, this is a bug. There is an internal defect of SOAP-2344 for this issue. This applies for the PUT and DELETE methods for a REST mock service.
I have the same issue with a PATCH request.
Use the following trick to get the body of the PUT and DELETE requests:
mockRequest.with {
if (method.toString() == 'PUT' || method.toString() == 'DELETE') {
InputStreamReader isr = new InputStreamReader(request.getInputStream(), "UTF-8")
BufferedReader br = new BufferedReader(isr)
StringBuilder sb = new StringBuilder()
while ((s=br.readLine())!=null) {
sb.append(s)
}
def requestBody = new groovy.json.JsonSlurper().parseText(sb.toString())
log.info "requestBody: " + requestBody
}
}
I use it on the project but I don't really remember how where I got the snippet from. I had to change some parts to make it work as far as I remember. Give it a try.
I have an application with following back-end-technologies: scala/slick in playframework. Front- and back-end communicate via REST.
Now what I want to do is simply return a created/inserted (updated) row back to the front-end of my application. I thought about doing something like this:
def createClient = Action.async { implicit request =>
request.body.asJson.map(_.validate[ClientModel]) match {
case c: JsSuccess[ClientModel] =>
clientDTO.createClient(c.get).map{
cnt => Ok(Json.obj("id" -> cnt.id))
}.recover {
case e: Exception => BadRequest("Could ssnotsdreate client")
}
}
}
My code compiles but it gives me this error message while running:
XMLHttpRequest cannot load http://localhost:9002/clients. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 500.
I read about adding CORS to my application but would prefer to solve it otherwise. I thought there has to be a proper, elegant way to return a just created/inserted object back to the front-end, since it should be a core feature of any client-server communication.
I'm relatively new to scala, so please don't get hung up on my code and rather view it as pseudo code. This is a rather general question. Thank you!
I'm pretty new to Scala, the Play Framework and Akka. In the project I currently work on, the user of the web application should be able to ask the server several things to do (like starting a particular computation) in an asynchronous way. If the server is done it should notify the user also async. I solve this demand by a WebSocket connection which is established when the user first connects with the Application and the WebSocket is handled by a UserActor, which is attached to the User Session:
def ws = WebSocket.tryAcceptWithActor[JsValue, JsValue] { implicit request =>
Future.successful(request.session.get(UID) match {
case None => Left(Forbidden)
case Some(uid) => Logger.info("WebSocket has accepted the request with uid " + uid)
Right(UserActor.props(uid))
})
}
Currently, the only thing the UserActor does is receiving messages from the WebSocket as JsValue. The UID of the session is generated when requesting index:
def index = Action { implicit request => {
val uid = request.session.get(UID).getOrElse {
counter += 1
counter.toString
}
Ok(views.html.index(uid)).withSession {
Logger.debug("create uid " + uid)
request.session + (UID -> uid)
}}
}
The UserActor should represent the actual user on the Server and thus include the logic of all actions that the user can perform on the Server. This works fine as long as I send all user interaction over the WebSocket.
Now what is the case with other user input, like form submission? The application includes a form whose data should not go over the WebSocket, but rather be submitted with a POST request (perhaps with AJAX) and bound in a controller to the Model like described in the documentation.
def saveContact = Action { implicit request =>
contactForm.bindFromRequest.fold(
formWithErrors => {
BadRequest(views.html.contact.form(formWithErrors))
},
contact => {
val contactId = Contact.save(contact)
Redirect(routes.Application.showContact(contactId)).flashing("success" -> "Contact saved!")
}
)
}
This example is taken from the Playframework documentation.
Now, how do I link the Form Submission handler with the UserActor? Say I want to tell the user actor that a form has been submitted. A trivial example would be that the UserActor sends one value of the form back over the WebSocket to the client as soon it is received. So basically the problem reduces to the issue that I want to send the UserActor Messages from any Controller.
I might come up with the idea to send all form data over the WebSocket, but I also want to realize the upload of large data in the future, which I want to tackle like described in this blog post. Then one scenario I could imagine is that the UserActor should be messaged for each chunk it receives.
I guess one problem is that the UserActor and the WebSocketActor are the same and I rather should split their logic, such that the UserActor is only associated with the Session, but I have no idea how to accomplish this. Maybe I need another actor, say a UserManager, which keeps track of present UserActors and enables access to UserActors?
Do you have any suggestions, recommendations or perhaps an example application which also deals with this case? Thank you very much in advance.
Best regards
Don't use the actor that you pass to tryAcceptWithActor as a representation of the User. It should represent a particular session with that user. Possibly, one of many concurrent sessions (multiple browsers, or tabs) a user could have open at a particular time.
Create a separate actor to represent the user and all of the actions it can perform. Now the session actors should forward their messages to the user actor. Traditional controller methods can also forward requests to the corresponding user actors.
I connect to twitter streaming API using Play 2.2 WS API in the code example below. I'm stuck trying to figure out how to disconnect from stream once it's established. Is there any proper way to do that rather than stopping application? Any help will be appreciated.
def watchTweets(keywords : String) = Action { implicit request =>
Logger.debug(s"watchTweets invoked with: $keywords")
val (tweetsOut, tweetChanel) = Concurrent.broadcast[JsValue]
WS.url(s"https://stream.twitter.com/1.1/statuses/filter.json?track=" + URLEncoder.encode(keywords, "UTF-8"))
.sign(OAuthCalculator(Twitter.KEY, Twitter.sessionTokenPair.get))
.postAndRetrieveStream("")(headers => Iteratee.foreach[Array[Byte]] { ba =>
val msg = new String(ba, "UTF-8")
Logger.debug(s"received message: $msg")
val tweet = Json.parse(msg)
tweetChanel.push(tweet)
}).flatMap(_.run)
Ok.chunked(tweetsOut &> Comet(callback = "parent.cometMessage")) }
This is a known issue... the answer is that you close the connection, but the problem is, the enumerator won't notice that the connection is closed until it tries to feed a tweet to the client, and that won't happen until it receives another tweet from Twitter, which might take a long time to happen.
This is of course a problem when doing Twitter streaming because Twitter will only let a user create one stream at a time, so that effectively means that you can't do a second stream until the first receives some data.
Unfortunately we don't have a work around as yet, but we are looking at introducing a new lower level streaming API into Play around the 2.4 time line, which will certainly allow this.
I'm developing an application using Play framework in scala. I have to handle the below use case in my application.
For a particular request from the browser to the play server the Play server should make an http request to some external server (for Eg: somesite.com) and send the response from this request back to the web browser.
I have written the below code to send the request to external serever in the controller.
val holder = WS.url("http://somesite.com")
val futureResponse = holder.get
Now how do I send back the response recieved from "somesite.com" back to the browser?
There's an example in the Play documentation for WS, under Using in a controller; I've adapted it to your scenario:
def showSomeSiteContent = Action.async {
WS.url("http://somesite.com").get().map { response =>
Ok(response.body)
}
}
The key thing to note is the idiomatic use of map() on the Future that you get back from the get call - code inside this map block will be executed once the Future has completed successfully.
The Action.async "wrapper" tells the Play framework that you'll be returning a Future[Response] and that you want it to do the necessary waiting for things to happen, as explained in the Handling Asynchronous Results documentation.
You may also be interested in dynamically returning the status and content type:
def showSomeSiteContent = Action.async {
WS.url("http://somesite.com").get().map { response =>
Status(response.status)(response.body).as(response.ahcResponse.getContentType)
}
}
Dynamic status could help if the URL/service you call fails to answer correctly.
Dynamic content type can be handy if your URL/service can return different content HTML/XML... depending on some dynamic parameter.