How to filter requests for access code in Play 2.1 - scala

I'd like to add a (per method / global) filter to requests, that simply rejects (404/403 page) any request that doesn't have a specific URL parameter.
I know Play has one-two mechanism to do this (e.g. register on Global.onRouteRequest()), so don't just send me a link to the documentation unless it contains a code sample that covers this question. I tried playing with the API but got a bit stuck.

Is this what you mean?
object Global extends WithFilters(AccessCheck)
object AccessCheck extends Filter with Results {
override def apply(next:RequestHeader => Result)(request:RequestHeader):Result =
request
.getQueryString("myCheck")
.map( myCheck => next(request))
.getOrElse(Forbidden)
}
http://www.playframework.com/documentation/2.1.0/ScalaInterceptors

If you are just trying to make some reusable code to filter requests on specific actions you my want to try creating an EssentialAction like this. This is known as action composition. This is what it would look like in the case you described. There is more information in the docs: http://www.playframework.com/documentation/2.1.1/ScalaActionsComposition
Note that you can do this in Play 2.0.X as well but EssentialAction doesn't exist, instead you use an Action, and there is just a little more syntax involved.
def RequireMyCheck(action: => EssentialAction): EssentialAction = {
EssentialAction { request =>
request
.getQueryString("myCheck")
.map( myCheck => action()(request))
.getOrElse(Forbidden)
}
}
You can use it like this:
def index = RequireMyCheck {
Action { request =>
Ok("Hello")
}
}

Related

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.

Create two or more APIs with same URL in play framework

I have use case where I need to read value from query string.
Currently I have two different APIs(Some other person has created the code) which maps to same URL
GET /service/class/:className/details controllers.Student.getStudentDetails(studentId)
GET /service/class/:className/details controllers.Student.getAllStudentsDetails()
If query string is present in URL then API1 should execute, otherwise API2.
As URL is same for both APIs, I am able to hit only get-student-details API(Because it has higher priority in routes file).
I am looking for alternatives to fix this problem.
As per my knowledge we don't need to create different APIs just to handle query strings.
I am thinking to merge 2 different APIs in single APIs which takes action depending upon presence of query string in request.
What I want to know is if there is way to execute two different APIs which maps to same URL(Only difference is with query string).
NOTE: I am using play 2.4.6.
I see few ways using a single controller function (say we chose getStudentDetails)
1) Having an Option parameter:
def getStudentDetails(studentId: Option[String]) = Action { studentId match {
case Some(id) => // do something
case None => // do something else
}
// ..
}
2) Look for your query string parameters inside your http request:
def getStudentDetails = Action { request =>
request.queryString.get("studentId") match {
case Some(list) => // do something...beware this is a List
case None => // do something else
}
//...
}

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.

Have a List in Play framework web service parameters

I have written this web service in play framework.
controller
def getByGenre(genre: String) = Action {
val result = Await.result(Movies.getByGenre(genre), 5 seconds)
Ok(toJson(result))
}
routes
GET /movies/genre/:genre controllers.MoviesController.getByGenre(genre: String)
However a user may select multiple Genre. Therefore I need to convert the genre parameter to a List[String]
I also need to know how to pass that Array parameter to the web service using CURL.
If you can pass the genres parameter as part of the query string, just repeat the parameter with different values and then retrieve it like this:
def getByGenre() = Action.async { implicit request =>
val genres = request.queryString.get("genres")
Movies.getByGenre(genres).map { movies =>
Ok(toJson(movies))
}
}
Your route will be:
GET /movies/genre controllers.MoviesController.getByGenre()
Also, notice that you will need to change the Movies.getByGenre signature to:
def getByGenre(genres: Option[Seq[String]]): Seq[Movies]
An final url will be something like #mfirry showed:
myhost.com/movies/genre?genre=action&genre=drama
Finally, as you may have noticed, I've removed the blocking code from you action. Using Await at your controller means that you action would be blocking for at least 5 seconds at the worst case scenario. I suggest you to take a look at the following page of Play docs:
https://www.playframework.com/documentation/2.5.x/ScalaAsync

Load the User object on each request in a controller, how to make this object available?

From what I understand controllers in play are singletons, so I'm not sure how to go about this.
In Rails I could simply load a user in the base_controller, and then in any controller that inherits from the base_controller the user object would be available for me to use.
In play, I'm not sure how this will work. Basically in each Action in a controller I want the user object to be available for me.
def someAction = {
val name = user.name
val age = user.age
Ok("hello")
}
Is this possible in play? I'm' sure it is but I can't seem to figure out way to do this.
I'm not sure you'll be able to make it quite as terse as Rails, but using Play's Action Composition style you can build up something quite flexible.
We start by creating a trait which knows how to build such a user, and wraps a normal Action, allowing the User to be obtained, and passed into the body:
trait UserAware {
def buildUserFromCookie(request:RequestHeader):Option[User] = {
request.cookies.get("myUserCookie").map { c =>
// Build up a User object from cookie contents
// ...
}
}
def cookieNotFound = Results.InternalServerError("Lost your session cookie :-(")
def UserAction(f: User => Request[AnyContent] => SimpleResult):Action[AnyContent] =
UserAction[AnyContent](BodyParsers.parse.anyContent)(f)
def UserAction[T](bodyParser:BodyParser[T])(f: (User) => Request[T] => SimpleResult):Action[T] = {
Action(bodyParser) { request =>
buildUserFromCookie(request).fold(cookieNotFound) ({ user =>
f(user)(request)
})
}
}
}
I'm going to assume that you have a session cookie that holds sufficient information to be able to recreate a User object. Whatever you need to do within buildUserFromCookie() is out of scope here.
I've defined two UserAction wrappers, one delegating to the other. The difference is whether you need a special body parser or not. Below you'll see it in use.
The second UserAction method is the interesting one - if you supply it with a method that can take a User and a Request, it will call it for you after creating the user, or bombing out if it can't find the cookie.
Here it is in use:
object MyController extends Controller with UserAware {
def doSomething = UserAction { implicit user => implicit request =>
Ok(s"The user's name is $user.")
}
def doSomethingJsonish = UserAction(parse.json) { implicit user => implicit request =>
Ok(s"The user's name is $user and their request body is JSON: ${request.body}")
}
}
With the overloaded UserActions, you can still use Play's Body Parsers to get access to a nicely-typed request body, and you've got the freshly-created User available as user.