Request.session.get(String) returns Option[String] How do I use this? - scala

I want to use a session value in pattern matching but since my request.get("profileType") returns Option[String] I cannot use it in pattern matching like I have in my code.
Here's my code snippet.
def editorProfile = Action { implicit request =>
request.session.get("profileType").toString() match {
case "editor" => {
request.session.get("userEmail").map {
userEmail => Ok(html.profile.editorProfile("my profile"))
}.getOrElse {
Unauthorized(html.error("Not logged in"))
}
}
}
}
Here is the error:
[MatchError: Some(editor) (of class java.lang.String)]
My question is. How do I use this Some(editor) from session.get in my pattern matching?

You should probably try to use a for comprehension because it might scale easier when you add more checks of a similar type.
val email = for {
profileType <- request.session.get("profileType") if profileType == "editor"
userEmail <- request.session.get("userEmail")
} yield userEmail
// email is of type Option[String] now, so we do the matching accordingly
email match {
case m: Some => Ok(html.profile.editorProfile("my profile"))
case None => Unauthorized(html.error("Not logged in or not an editor."))
}
You can of course write all that in an even more concise way but as a beginner, it does not hurt being more explicit.
Addition:
If you want to use the mail address later on, you could change it to:
email match {
case Some(address) => Ok(html.profile.editorProfileWithEmail("my profile", address))
case None => Unauthorized(html.error("Not logged in or not an editor."))
}

You call toString on Option[String] and get "Some(editor)". Instead you must match on this:
request.session.get("profileType") match {
case Some("editor") => { /* your code */}
case _ => /* something else */
}
Note that I added default case _ =>. Without it you can get MatchError if session didn't contains "profileType" attribute or attribute has another value.

Related

"Redirect" to an external URL using play framework 2.7

I am trying to redirect to an external URL with some authorization code attached to it. I am using the "Redirect" function available in play framework using Scala. But instead of redirecting to the provided URL, the message in "Ok" gets printed and is not redirected
I am a beginner in Play and Scala. It is my understanding that an "Action" should send a "Result". This "Result" can either be "Ok" or a "Redirect". In the below code:
1) If I don't mention "Ok", there is a compile error
2) If I execute the code below, it doesn't get redirected, it just prints the message in "Ok"
// This is inside a controller
// it is defined as a GET in the routes file
def test = Action { implicit request =>
async {
await(userAuth.getAuth()) match{
case Some(userAuth) if <>
val url = <FunctionReturnsUrlwithcode>
Redirect(url)
case _ if flag
val url = <FunctionReturnsUrlwithcode>
Redirect(url)
}
Ok("Some message") // Without this , there is an error
}
I assume this is pseudocode, since that pattern matching isn't syntactically correct...
Your pattern matching isn't exhaustive. For example:
def test(): String = {
val x = Some(1)
x match {
case Some(y) if y == 2 => return "matched 1"
case _ if false == true => return "matched 2"
}
"matched nothing"
}
The above code will return "matched nothing", since 1 != 2 and false != true. There needs to be a default case, otherwise if any of the specified conditions aren't met it'll ignore the pattern matching altogether.
In your case, I'm guessing that neither of the conditions in your pattern matching are being met. Therefore, the pattern matching is skipped over and Ok(whatever) is returned - if you take out the Ok, your app will blow up since an Action must return a Result. Your code will also return the Ok if you write it like this:
def test = Action { implicit request =>
async {
await(userAuth.getAuth()) match{
case Some(userAuth) if <> =>
val url = <FunctionReturnsUrlwithcode>
Redirect(url)
case _ if flag =>
val url = <FunctionReturnsUrlwithcode>
Redirect(url)
case _ =>
Ok("Some message")
}
}
}
Also,
This "Result" can either be "Ok" or a "Redirect"
This is not true; it isn't limited to only two values. It can be a number of other things, such as NoContent, Created, BadRequest, InternalServerError, etc. (basically any valid HTTP status).
You can try the below:
def test: Action[AnyContent] = Action.async { implicit request =>
//your logic
async {
await(userAuth.getAuth()) match{
case Some(userAuth) if <> =>
val url = <FunctionReturnsUrlwithcode>
(Redirect(url, Map("traceid"-> Set("trace")))
case _ if flag =>
val url = <FunctionReturnsUrlwithcode>
(Redirect(url, Map("traceid"-> Set("trace")))
case _ =>
Ok("Some message")
}
}

How can an action convey that it has no body using a type?

An action in the controller have a type Action[A], which means that the body is an A (i.e should parse to A).
I'd like to look at an action's signature and know if it has no body, which is useful for GET requests for example.
e.g here's a code example with two actions, one that accepts a Person in the body and one that does not have a body:
case class Person(name: String)
implicit val personFormats: Format[Person] = Json.format[Person]
val people: mutable.Set[Person] = mutable.Set(Person("alice"), Person("bob"))
/** here it is clear that the body should contain a person info, since the method returns `Action[Person]` */
def createPerson(): Action[Person] =
Action(parse.json[Person]) { request: Request[Person] =>
val person: Person = request.body
if (people.add(person))
Ok(s"added ${person.name}")
else
Ok(s"${person.name} is already there :) nothing special to do")
}
/** Can it be clearer from the signature that there's no body? */
def findPerson(name: String): Action[AnyContent] =
Action {
people.find(_.name == name) match {
case Some(person) => Ok(Json.toJson(person))
case None => NotFound(s"no person named $name")
}
}
When I look at the body of the second action, findPerson, it is clear from Action(parse.empty) that the body is empty.
How can it be clear from the signature as well without messing up the body?
Returning Action[AnyContentAsEmpty] cannot work because play.api.mvc.AnyContentAsEmpty is an object.
There's the following version, where we pass parse.empty as the parser, and it would work, but request is unused, and I wonder if there's another way:
def findPerson2(name: String): Action[Unit] =
Action(parse.empty) { request =>
people.find(_.name == name) match {
case Some(person) => Ok(Json.toJson(person))
case None => NotFound(s"no person named $name")
}
}
Consider EssentialAction which by-design does not have a body parser like so
def findPerson(name: String) =
EssentialAction { _ =>
people.find(_.name == name) match {
case Some(person) => Accumulator.done(Ok(Json.toJson(person)))
case None => Accumulator.done(NotFound(s"no person named $name"))
}
}
or ActionBuilder.IgnoringBody() like so
val ignoringBodyAction = new ActionBuilder.IgnoringBody()(executionContext)
def findPerson(name: String) =
ignoringBodyAction {
people.find(_.name == name) match {
case Some(person) => Ok(Json.toJson(person))
case None => NotFound(s"no person named $name")
}
}

How to check if case class parameter has value or not in Scala

I have a case class QueryParamsas follows:
case class QueryParams(
limit: Option[Integer] = None,
refresh: Option[Boolean] = None,
organisationalUnit: Option[String] = None)
These values limit,refresh,organisationalUnit are actually passed as query parameters in request url for play application.
I need to write a code to check if request URL contains any value for organisationalUnit and if yes I need to throw error .If no, I need to proceed with further operations.
Can anyone help me here
Options are quite good for this kind of thing:
val params: QueryParams = ???
params.organizationalUnit.foreach(_ => throw new Exception("your error message"))
In this way you'll throw only if organizationalUnit is defined. You can also express it as follows:
for (_ <- params.organizationalUnit) {
throw new Exception("your error message")
}
Or alternatively:
if (params.organizationalUnit.isDefined) {
throw new Exception("your error message")
}
The latter is probably the most readable, even though it may not be recognized as very idiomatic according to certain coding styles.
The answer from stefanobaghino is good but I prefer pattern matching for such cases:
params.organisationalUnit match {
case Some(_) => // processing
case _ => //logging
}
If you need other values you can match the whole instance
params match {
case QueryParams(Some(limit), Some(refresh), Some(organisationalUnit)) =>
case QueryParams(mayBeLimit, mayBeRefresh, Some(organisationalUnit)) =>
case _ =>
}

How to break after response in Play (Scala)

I am new to Play Framework using Scala. I want to evaluate a condition and in that condition evaluates to true, I want to send a response and exit at that point. However, the code below that I am trying continues till the end.
I tried breaking with a return statement - However, I get a type mismatch. Can someone help me out with this?
def hello = Action { request =>
if (true) {
Ok("in If")
// Return at this point
}
print("This line should not be printed")
Ok("final")
}
EDIT
Assume a GET call is being made with 4 parameters - name, age, married, spouse. I want to make sure all 3 params (name, age, married) are passed in, and if married is true, check if spouse is passed in. If this validation fails, I want to respond saying Bad Request. Else, continue with logic. How do I write this?
Here is an alternative way to do it:
case class QueryInput(name: String, age: Int, married: Boolean, spouse: Option[String]) {
def validated = if(married && spouse.isEmpty) None else Some(this)
}
def validateInput(request: RequestHeader) = {
val input = for {
name <- request.queryString.get("name").flatMap(_.headOption)
age <- request.queryString.get("age").flatMap(_.headOption.flatMap(a=>Try(a.toInt).toOption))
married <- request.queryString.get("married").flatMap(_.headOption.map(_=="true"))
} yield {
QueryInput(name, age, married, request.queryString.get("spouse").flatMap(_.headOption))
}
input.flatMap(_.validated)
}
def hello() = Action { request =>
validateInput(request) match {
case Some(input) => Ok(input.toString())
case None => BadRequest
}
}
In fact, there are many options. You could also play with the Either class to do validation: Left value to accumulate errors and return bad request, right value to construct your validated input.
My recommendation would be to have a method for validating the parameters. Then do a simple if/else to check if the parameters are valid and return a success or a general error.
If you really want a specific
First thing:
When the block evaluates, all of its expressions and declarations are processed in order, and then the block returns the value of the last expression as its own value.
Second: don't use return.
And the third one is a Play Framework way of resolving your problem: action composition. Though I would not say that it is trivial.
You can do this, by putting a return Ok in but really, thats not the scala way. What you want to do is to change your mindset and imagine everything as a function. If you didnt know, if-then-else always returns a value. For example, you can actually write if this way:
def hello = Action { request =>
val result = if (true) {
Ok("foo")
} else {
Ok("bar")
}
result
}
of course, an even more scala way is to use matchers
def hello = Action { request =>
val result = true match {
case true => Ok("foo")
case _ => Ok("bar")
}
result
}
Take that one step further and you dont even need to specify the result object at all, because scala figures out the returning object based on the last object returned/created.
def hello = Action { request =>
true match {
case true => Ok("foo")
case _ => Ok("bar")
}
}
EDIT: TO answer the OP's edit, you still want to use the matcher. Assuming your vals are options, heres what you do:
def hello(nameOpt:Option[String], ageOpt:Option[String], marriedOpt:Option[String]) = Action { request =>
(nameOpt, ageOpt, marriedOpt) match {
case (Some(name), Some(age), Some(married)) => Ok("all 3 are given")
case (Some(name), Some(age), _) => Ok("all 2 are given")
// functionally same as above
// case (Some(name), Some(age), None) => Ok("all 2 are given")
// some combination of the above
case (None, None, Some(married)) => Ok("married but no name or age")
// default case
case _ => Ok("bar")
}
}

How to properly use future/actorSelection/resolveOne in Play app?

Below is my code:
def runAsync(crewType: String) = Action.async {
val temp: Future[Result] = Future(Crew.findCaptainByCrewType(crewType) match {
case None =>
BadRequest(s"Invalid crew name provided: $crewType")
case Some(crew) =>
system.actorSelection(s"/user/${crew.cptName}").resolveOne().map { actorRef =>
Ok(println("hi hi"))
}
})
temp
}
I don't understand why this doesn't work?
My objective is to have user pass in a name, which then I try to find an actor with that name using the actorSelection and resolveOne. I assume I am using it incorrectly?!
ActorSelection.resolveOne() returns a Future[ActorRef], and because you are inside a Future(...) you get a Future[Future[Result]] in case of a valid crewname.
You can solve this by using flatMap in which case you should also return a Future in case of an invalid crewname (None).
Unrelated: You can also leave out the temp value and can replace the pattern matching on Option by Option.fold.
def runAsync(crewType: String) = Action.async {
Future(Crew.findCaptainByCrewType(crewType)).flatMap( _.fold(
Future.successful(BadRequest(s"Invalid crew name provided: $crewType"))
)( crew =>
system.actorSelection(s"/user/${crew.cptName}").resolveOne().map {
actorRef => Ok(println("hi hi")) // not sure you want println here
}
))
}