Play scala Oauth Twitter example and redirect - scala

The play example for using Oauth and Twitter is show below.
In the Play Framework I am still learning how to use redirects and routes. How would you set up the routes file and the Appliction.scala file to handle this redirect?
Redirect(routes.Application.index).withSession("token" -> t.token, "secret" -> t.secret)
Would the routes be something like this?
GET /index controllers.Application.index(String, String)
Link to Play Framework documentation with the example code http://www.playframework.com/documentation/2.0/ScalaOAuth
object Twitter extends Controller {
val KEY = ConsumerKey("xxxxx", "xxxxx")
val TWITTER = OAuth(ServiceInfo(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize", KEY),
false)
def authenticate = Action { request =>
request.queryString.get("oauth_verifier").flatMap(_.headOption).map { verifier =>
val tokenPair = sessionTokenPair(request).get
// We got the verifier; now get the access token, store it and back to index
TWITTER.retrieveAccessToken(tokenPair, verifier) match {
case Right(t) => {
// We received the authorized tokens in the OAuth object - store it before we proceed
Redirect(routes.Application.index).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
}
}.getOrElse(
TWITTER.retrieveRequestToken("http://localhost:9000/auth") match {
case Right(t) => {
// We received the unauthorized tokens in the OAuth object - store it before we proceed
Redirect(TWITTER.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
})
}
def sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
for {
token <- request.session.get("token")
secret <- request.session.get("secret")
} yield {
RequestToken(token, secret)
}
}
}

It turned out that the reasons I had so many intermittent problems with routes and redirect was a combination of the versions of play, version of scala and the version of ScalaIDE for Eclipse. Using Play version 2.2.3, scala version 2.10.4 and ScalaIDE version 2.10.x solved the routes and redirect problems.
The following import statements are needed for the Twitter example.
import play.api.libs.oauth.ConsumerKey
import play.api.libs.oauth.ServiceInfo
import play.api.libs.oauth.OAuth
import play.api.libs.oauth.RequestToken

If your route is like this:
GET /index controllers.Application.index(param1:String, param2:String)
Then the reverse route would look like this:
routes.Application.index("p1", "p2")
Which would result in something like this:
/index?param1=p1&param2=p2
Make sure that the documentation you are looking at is of the correct version, for 2.2.x you would need this url: http://www.playframework.com/documentation/2.2.x/ScalaOAuth

Related

Intelllij doesn't support Play Framework very well?

I am using Intellij Idea + Scala Plugin + Play framework 2.6.0 to do web development.
I have a FruitController, its definition is:
def saveFruit = Action(BodyParsers.parse.json) { request =>
import FruitImplicits._
val fruitResult = request.body.validate[Fruit]
fruitResult.fold(
errors => {
BadRequest(Json.obj("status" -> "KO", "message" -> JsError.toJson(errors)))
},
fruit => {
println(s"Fruit is saved, the result is :$fruit")
Ok(Json.obj("status" -> "OK", "message" -> ("Fruit '" + fruit.name + "' saved.")))
}
)
}
The Intellij idea complains Missing parameter type:request for the request in the first line: Action(BodyParsers.parse.json) { request =>
But I could run the code successfully, so Intellij Idea has been mistakenly reported the error, I would ask how to get Intellij Idea to work well for this code
When I explicitly specify the type of the request: Request[JsValue], the problem is gone:
def saveFruit = Action(parse.json) { request: Request[JsValue] =>

WSClient - Too Many Open Files

I'm working with Play Framework 2.4 on CentOS 6 and my application is throwing this exception:
java.net.SocketException: Too many open files
I've searched a lot of topics on Stack Overflow and tried the solutions:
Increase the number of open files to 65535;
Change hard and soft limits on /etc/security/limits.conf;
Change the value of fs.file-max on /etc/sysctl.conf;
Reduced the timeout on file /proc/sys/net/ipv4/tcp_fin_timeout;
The error keeps happening. On another sites, i've found people that are facing the same problem because they weren't calling the method close() from WSClient but in my case, i'm working with dependency injection:
#Singleton
class RabbitService #Inject()(ws:WSClient) {
def myFunction() {
ws.url(“url”).withHeaders(
"Content-type" -> "application/json",
"Authorization" -> ("Bearer " + authorization))
.post(message)
.map(r => {
r.status match {
case 201 => Logger.debug("It Rocks")
case _ => Logger.error(s"It sucks")
}
})
}
}
If i change my implementation to await the result, it work's like a charm but the performance is very poor - and i would like to use map function instead wait the result:
#Singleton
class RabbitService #Inject()(ws:WSClient) {
def myFunction() {
val response = ws.url("url")
.withHeaders(
"Content-type" -> "application/json",
"Authorization" -> ("Bearer " + authorization))
.post(message)
Try(Await.result(response, 1 seconds)) match {
case Success(r) =>
if(r.status == 201) {
Logger.debug(s"It rocks")
} else {
Logger.error(s"It sucks")
}
case Failure(e) => Logger.error(e.getMessage, e)
}
}
}
Anyone have an idea how can i fix this error? I've tried everything but without success.
If anyone is facing the same problem, you need to configure WSClient on application.conf - need to set maxConnectionsTotal and maxConnectionsPerHost.
This is how I solved this problem.
https://www.playframework.com/documentation/2.5.x/ScalaWS

How to host static resources in finagle

I am trying to host static resources, like javascript and css files, in finagle.
I've managed to get it to work, but I have to specifically configure every route to a resource folder in my routing service. For example:
def build():RoutingService[Request with Request] = {
val routingService = RoutingService.byPathObject {
case Root => ControllerRegistry.rootController.root()
case Root / "public" / resource => ControllerRegistry.publicController.findPublic()
case Root / "public" / "bootstrap"/ "css" / resource => ControllerRegistry.publicController.findPublic()
}
routingService
}
and
def findPublic(): Service[Request, Response] = {
val findPublic = new Service[Request, Response] {
def apply(request: Request) = {
Future {
val resource = Path(request.path) match {
case Root / "public" / resource => getResourceText(s"/public/$resource")
case Root / "public" / "bootstrap" / "css" / resource => getResourceText(s"/public/bootstrap/css/$resource")
case _ => throw new IllegalStateException
}
val response = Response()
response.setContent(copiedBuffer(resource, UTF_8))
response
}
}
}
findPublic
}
Now I can get any resource in public and public/bootstrap/css, but I can't get public/bootstrap/js without more configuration.
TLDR: Finagle is not exactly the right library to do what you want. You could use something like Finatra which is built on top of finagle.
Long version:
Finagle is designed to build distributed systems, it's not a web framework like ruby on rails (even if finagle-http provides very basic feature for doing that). It makes easy to build services that interact with each other (and take care of load-balancing, timeout, disconnection, back-pressure, distributed tracing, ...)
We have, at Twitter, a web framework library built on top of finagle, but it's not yet open-sourced, in the meantime you can use Finatra.

How to test remote (production) Scalatra web service with Specs2?

I'm using Specs2 to test my Scalatra web service.
class APISpec extends ScalatraSpec {
def is = "Simple test" ^
"invalid key should return status 401" ! root401^
addServlet(new APIServlet(),"/*")
def root401 = get("/payments") {
status must_== 401
}
}
This tests the web service locally (localhost). Now I would like to perform the same tests to the production Jetty server. Ideally, I would be able to do this by only changing some URL. Is this possible at all ? Or do I have to write my own (possible duplicate) testing code for the production server?
I don't know how Scalatra manages its URLs but one thing you can do in specs2 is control parameters from the command-line:
class APISpec extends ScalatraSpec with CommandLineArguments { def is = s2"""
Simple test
invalid key should return status 401 $root401
${addServlet(new APIServlet(),s"$baseUrl/*")}
"""
def baseUrl = {
// assuming that you passed 'url www.production.com' on the command line
val args = arguments.commandLine.split(" ")
args.zip(args.drop(1)).find { case (name, value) if name == "url" => value }.
getOrElse("localhost:8080")
}
def root401 = get(s"$baseUrl/payments") {
status must_== 401
}
}

ReactiveMongo plugin play framework seems to restart with every query

I am trying to write a play! framework 2.1 application with ReactiveMongo, following this sample. however, with every call to the plugin, it seems that the application hangs after the operation completes, than the pluging closes and restarts, and we move on. functionality work, but i am not sure if it's not crashing and restarting along the way.
code:
def db = ReactiveMongoPlugin.db
def nodesCollection = db("nodes")
def index = Action {implicit request =>
Async {
Logger.debug("serving nodes list")
implicit val nodeReader = Node.Node7BSONReader
val query = BSONDocument(
"$query" -> BSONDocument()
)
val found = nodesCollection.find(query)
found.toList.map { nodes =>
Logger.debug("returning nodes list to requester")
Ok(views.html.nodes.nodes(nodes))
}
}
}
def showCreationForm = Action { implicit request =>
Ok(views.html.nodes.editNode(None, Node.nodeCredForm))
}
def create = Action { implicit request =>
Node.nodeCredForm.bindFromRequest.fold(
errors => {
Ok(views.html.nodes.editNode(None, errors))
},
node => AsyncResult {
Node.createNode(node._1, node._2, node._3) match {
case Right(myNode) => {
nodesCollection.insert(myNode).map { _ =>
Redirect(routes.Nodes.index).flashing("success" -> "Node Added")
}
}
case Left(message) => {
Future(Redirect(routes.Nodes.index).flashing("error" -> message))
}
}
}
)
}
logging:
[debug] application - in Node constructor
[debug] application - done inseting, redirecting to nodes page
--- (RELOAD) ---
[info] application - ReactiveMongoPlugin stops, closing connections...
[info] application - ReactiveMongo stopped. [Success(Closed)]
[info] application - ReactiveMongoPlugin starting...
what is wrong with this picture?
There seems nothing wrong with that picture. If you only showed me that log output I would say you would have changed a file in you play application. Which would cause the application to reload.
I guess that is not the case, so your database is probably located within your application directory, causing the application to reload on each change. Where is your database located?