How to get the correct parameter validation error - scala

I have a simple route, where the parameters should be extracted into case classes:
val myRoute: Route =
get {
path("resource") {
parameters('foo, 'x.as[Int]).as(FooParams) { params =>
...
} ~
parameters('bar, 'x.as[Int]).as(BarParams) { params =>
...
}
}
}
case class FooParams(foo: String, x: Int) {
require(x > 1 && x < 10, "x for foos must be between 2 and 9")
}
case class BarParams(bar: String, x: Int) {
require(x > 10 && x < 20, "x for bars must be between 11 and 19")
}
The case classes should validate the input, so invalid input would be rejected with a 400.
The rejection happens, but with a 404 and the error message is misleading
I expect it to be x for foos must be between 2 and 9 for .../resource?foo=a&x=0 but it is Request is missing required query parameter 'bar'
Same for bars, while I expect .../resource?bar=a&x=0 to result in a 400 with x for bars must be between 11 and 19, it responds with a 404 with Request is missing required query parameter 'foo'.
What am I misunderstanding here and how to fix it?
akka-http 2.0.3
EDIT
4lex1v's solution works for me. What bothers me a bit is that I am deliberately abandoning the help the framework offers me: I have to handle the case where both foo and bar are missing 'manually'. Same goes for the rejections on x ranges. OTOH, the code is much more explicit, including the handling for the case where both foo and bar are given and the MissingQueryParamRejection can be customized when both are missing:
val myRoute2: Route =
(get & path("resource")) {
parameters('foo ?, 'bar ?, 'x.as[Int]) {
case (Some(foo), None, x) if x > 1 && x < 10 => {
val params = FooParams(foo, x)
...
}
case (Some(foo), None, x) => reject(MalformedQueryParamRejection("x", s"x for foos must be between 2 and 10 but was $x"))
case (None, Some(bar), x) if x > 10 && x < 20 => {
val params = BarParams(bar, x)
...
}
case (None, Some(bar), x) => reject(MalformedQueryParamRejection("x", s"x for bars must be between 11 and 19 but was $x"))
case (Some(foo), Some(bar), x) => reject(MalformedQueryParamRejection("bar", "expecting either foo or bar, received both"))
case (None, None, x) => reject(MissingQueryParamRejection("foo or bar"))
}
}

I think the main part of the issue you are seeing comes from how your route is defined. By defining both of those possible parameter sets under the path "resource", then when it misses on the foo param you end up with a MissingParemeterRejection at the head of the list of rejections. A ValidationRejection ends up in there too, but the default rejection handler must prefer the MissingParameterRejection when deciding whats status code and message to convey to the caller. If you simply redefined your routes like so:
val myRoute: Route =
get {
path("resource") {
parameters('foo, 'x.as[Int]).as(FooParams) { params =>
...
} ~
}
path("resource2"){
parameters('bar, 'x.as[Int]).as(BarParams) { params =>
...
}
}
}
Then everything works as expected. In this case, it doesn't even attempt to evaluate the params until it has accepted the root path. And with each root path having a different param set, there is no chance of getting that unnecessary missing param exception at the head of the list.
Now if that's not an acceptable alternative, then you can wrap that route with something like mapRejections to remove the unnecessary missing param rejection if it contains a validation rejection. Something like this:
val validationWins = mapRejections{ rej =>
val mapped = rej.filter(_.isInstanceOf[ValidationRejection])
if (mapped.isEmpty) rej else mapped
}
val myRoute =
get {
path("resource") {
validationWins{
parameters('foo, 'x.as[Int]).as(FooParams) { params =>
complete(StatusCodes.OK)
} ~
parameters('bar, 'x.as[Int]).as(BarParams) { params =>
complete(StatusCodes.OK)
}
}
}
Ideally, I prefer to use cancelRejections in my route tree to remove things that don't matter going forward in the tree, but there wasn't a clean place to do that, so I used mapRejections instead.

I wouldn't do it with two distinct parameters directives, instead i would advice to use one and make your parameters as option, i.e parameters('foo?, 'bar?, x.as[Int]). This directive would extract the data you need, which you can later match on and convert the the case you need, something like this:
(get & path("...")) {
parameters('foo?, 'bar?, x.as[Int]) {
case (None, Some(bar), x) => BarParams(bar, x)
case (Some(foo), None, x) => FooParams(foo, x)
/**
* Here comes you Rejection (you can make your own)
*/
case _ => reject(MalfromedParametersRejection)
}
}
Another thing i'd consider a bad practice using require in constructor, given solution allows you to use guards to handle the case you've described:
parameters('foo?, 'bar?, x.as[Int]) {
case (None, Some(bar), x) if x > 1 && x < 10 => BarParams(bar, x)
//...
}

Related

scala using calculations from pattern matching's guard (if) in body

I'm using pattern matching in scala a lot. Many times I need to do some calculations in guard part and sometimes they are pretty expensive. Is there any way to bind calculated values to separate value?
//i wan't to use result of prettyExpensiveFunc in body safely
people.collect {
case ...
case Some(Right((x, y))) if prettyExpensiveFunc(x, y) > 0 => prettyExpensiveFunc(x)
}
//ideally something like that could be helpful, but it doesn't compile:
people.collect {
case ...
case Some(Right((x, y))) if {val z = prettyExpensiveFunc(x, y); y > 0} => z
}
//this sollution works but it isn't safe for some `Seq` types and is risky when more cases are used.
var cache:Int = 0
people.collect {
case ...
case Some(Right((x, y))) if {cache = prettyExpensiveFunc(x, y); cache > 0} => cache
}
Is there any better solution?
ps: Example is simplified and I don't expect anwers that shows that I don't need pattern matching here.
You can use cats.Eval to make expensive calculations lazy and memoizable, create Evals using .map and extract .value (calculated at most once - if needed) in .collect
values.map { value =>
val expensiveCheck1 = Eval.later { prettyExpensiveFunc(value) }
val expensiveCheck2 = Eval.later { anotherExpensiveFunc(value) }
(value, expensiveCheck1, expensiveCheck2)
}.collect {
case (value, lazyResult1, _) if lazyResult1.value > 0 => ...
case (value, _, lazyResult2) if lazyResult2.value > 0 => ...
case (value, lazyResult1, lazyResult2) if lazyResult1.value > lazyResult2.value => ...
...
}
I don't see a way of doing what you want without creating some implementation of lazy evaluation, and if you have to use one, you might as well use existing one instead of rolling one yourself.
EDIT. Just in case you haven't noticed - you aren't losing the ability to pattern match by using tuple here:
values.map {
// originial value -> lazily evaluated memoized expensive calculation
case a # Some(Right((x, y)) => a -> Some(Eval.later(prettyExpensiveFunc(x, y)))
case a => a -> None
}.collect {
// match type and calculation
...
case (Some(Right((x, y))), Some(lazyResult)) if lazyResult.value > 0 => ...
...
}
Why not run the function first for every element and then work with a tuple?
Seq(1,2,3,4,5).map(e => (e, prettyExpensiveFunc(e))).collect {
case ...
case (x, y) if y => y
}
I tried own matchers and effect is somehow OK, but not perfect. My matcher is untyped, and it is bit ugly to make it fully typed.
class Matcher[T,E](f:PartialFunction[T, E]) {
def unapply(z: T): Option[E] = if (f.isDefinedAt(z)) Some(f(z)) else None
}
def newMatcherAny[E](f:PartialFunction[Any, E]) = new Matcher(f)
def newMatcher[T,E](f:PartialFunction[T, E]) = new Matcher(f)
def prettyExpensiveFunc(x:Int) = {println(s"-- prettyExpensiveFunc($x)"); x%2+x*x}
val x = Seq(
Some(Right(22)),
Some(Right(10)),
Some(Left("Oh now")),
None
)
val PersonAgeRank = newMatcherAny { case Some(Right(x:Int)) => (x, prettyExpensiveFunc(x)) }
x.collect {
case PersonAgeRank(age, rank) if rank > 100 => println("age:"+age + " rank:" + rank)
}
https://scalafiddle.io/sf/hFbcAqH/3

map expression in case clause in scala pattern matching

I have a configuration value that matches to one of the values in a map and depending on to which it matches i take an action. Here is some sample code of what i am trying to do
val x = 1 // or 2 or 3
val config = Map("c1"-> 1, "c2"-> 2, "c3"-> 3)
x match {
case config("c1") =>
println("1")
case config("c2") =>
println("2")
case config("c3") =>
println("3")
}
Now this should print 1 because config("c1") evaluates to 1 but it gives error
error: value config is not a case class, nor does it have an unapply/unapplySeq member
case config("c1") =>
Similarly for the other 2 cases. Why should i have an unapply here? Any pointers?
An expression like that looks like an extractor, hence the message about unapply/unapplySeq methods. If you don't want to use an extractor but just want to match against a plain value, you need to store that value in a stable identifier - you can't use an arbitrary expression as a match case:
val case1 = config("c1")
x match {
case case1 => println("1")
...
}
To the best of my knowledge, in Scala, x match {case config("c1") gets translated to config.unapply(x) with the branching dependent on the result of the unapply method. As Imm already mentioned in his answer, this isn't the case for stable identifiers (literals and val), and I'd encourage you to use his solution.
Nevertheless, to show you how you could solve the problem using extractors, I'd like to post a different solution:
def main(args: Array[String]): Unit = {
object config {
val configData = Map("c1" -> 1, "c2" -> 2, "c3" -> 3)
def unapply(value: Int): Option[String] = configData find (_._2 == value) map (_._1)
}
1 to 4 foreach {
case config("c1") => println("1")
case config("c2") => println("2")
case config("c3") => println("3")
case _ => println("no match")
}
}
I changed the match for a foreach to show the different results, but this has no effect on the implementation. This would print:
1
2
3
no match
As you can see, case config("c1") now calls the unapply method and checks whether the result is Some("c1"). Note that this is inverse to how you'd use a map: The key is searched according to the value. However, this makes sense: If in the map, "c1" and "c2" both map to 1, then 1 matches both, the same way _ matches everything, in our case even 4 which is not configured.
Here's also a very brief tutorial on extractors. I don't find it particularly good, because both, the returned type and the argument type are Int, but it might help you understand what's going on.
As others have stated, with x match { case config("c1") => ..., scala looks for an extractor by the name of config (something with an unapply method that takes a single value and returns an Optional value); Making pattern matching work this way seems like an abuse of the pattern, and I would not use an extractor for this.
Personally, I would recommend one of the following:
if (x == config("c1"))
println("1")
else if (x == config("c2"))
println("2")
else ...
Or, if you're set on using a match statement, you can use conditionals like this:
x match {
case _ if x == config("c1") =>
println("1")
case _ if x == config("c2") =>
println("2")
case _ if x == config("c3") =>
println("3")
}
Not as clean; unfortunately, there isn't a way to invoke a method call literally where the extractor goes. You can use back-ticks to tell scala "match against the value of this variable" (rather than default behavior, which would yield the value named as that variable):
val (c1,c2,c3) = (config("c1"), config("c2"), config("c3"))
x match {
case `c1` =>
println("1")
case `c2` =>
println("2")
case `c3` =>
println("3")
}
Finally, if your goal is to reverse-apply a map, maybe try this instead?
scala> Map("a" -> 1).map { case (k,v) => (v,k) }
res0: scala.collection.immutable.Map[Int,String] = Map(1 -> a)

Making code more functionally readable

I am looking at following snippet. When map-getOrElse and nested patten matching increases in the code it doesn't look so elegant. What better options do you suggest?
case MyMessage =>
val image = (request \ "image").asOpt[String]
image.map { im =>
val conf = (request \ "confirmation").asOpt[String]
conf.map { cf =>
//code to retrieve ride
ride match {
case Some(r) =>
if (booleanCondition) sender ! SuccessCommand(JsBoolean(true), command)
else sender ! FailureCommand("Problem updating", command)
case None => sender ! FailureCommand("Ride empty", command)
}
} getOrElse (sender ! FailureCommand("Missing number", command))
} getOrElse (sender ! FailureCommand("Missing image", command))
Whenever you are mapping over an Option with a function that produces an Option, you should consider whether you should be using flatMap:
def f(x: Int): Option[Int] = Some(x + 1)
f(1).flatMap(x => f(x)).flatMap(y => f(y)) // Some(4)
f(1).flatMap(x => f(x)).flatMap(y => f(y)).getOrElse(0) // 4
You can also use for-comprehensions for this, which is really nice for having clean code when you have long chains of these:
(for(x <- f(1); y <- f(x); z <- f(y)) yield z).getOrElse(0)
Another way to tackle this is to return Either[Command,String] from various helper functions, rather than Option. This would then allow you to use a for comprehension, something like the following:
val result = for {
i <- getImage().right
c <- getConf().right
r <- getRide().right
z <- check(r).right
} yield z
// extract either left or right, whichever is occupied
sender ! result.fold(identity, _ => success())
This has the desired property that we stop as soon as we encounter an error, and capture that specific error - or proceed to a successful conclusion.
I think you should be able to collapse a lot of this into Option.fold(), roughly as follows:
case MyMessage =>
sender !
getImage().fold(fail("Missing image")) { im =>
getConf().fold(fail("Missing number")) { conf => // conf isn't used
getRide().fold(fail("Ride empty")) { r =>
if (booleanCondition) succeed(true)
else fail("Problem updating")
}
}
}
This turns out a bit more concise than flatMap and orElse in this situation (see below)
Option.fold(ifEmpty){f} returns ifEmpty (evaluated lazily) if the option was empty, or evaluates the function f if the option was full.
The above code assumes you create helper functions for getting the various Options (or you could inline the relevant code). It also assumes you pull out the creation of commands into a helper function or two, to avoid all the duplicate references to command.
For comparison, a solution using flatMap looks something like:
case MyMessage =>
sender !
getImage().flatMap { im =>
getConf().flatMap { conf =>
getRide().flatMap { r =>
if (booleanCondition) Some(succeed(true))
else Some(fail("Problem updating"))
}.orElse(Some(fail("Ride Empty")))
}.orElse(Some(fail("Missing number")))
}.getOrElse(fail("Missing image"))
which you could shorten very slightly by having variants of your helper methods (fail and succeed) that return Some[Command] rather than Command

Idiomatic "do until" collection updating

Scenario:
val col: IndexedSeq[Array[Char]] = for (i <- 1 to n) yield {
val x = for (j <- 1 to m) yield 'x'
x.toArray
}
This is a fairly simple char matrix. toArray used to allow updating.
var west = last.x - 1
while (west >= 0 && arr(last.y)(west) == '.') {
arr(last.y)(west) = ch;
west -= 1;
}
This is updating all . to ch until a non-dot char is found.
Generically, update until stop condition is met, unknown number of steps.
What is the idiomatic equivalent of it?
Conclusion
It's doable, but the trade-off isn't worth it, a lot of performance is lost to expressive syntax when the collection allows updating.
Your wish for a "cleaner, more idiomatic" solution is of course a little fuzzy, because it leaves a lot of room for subjectivity. In general, I'd consider a tail-recursive updating routine more idiomatic, but it might not be "cleaner" if you're more familiar with a non-functional programming style. I came up with this:
#tailrec
def update(arr:List[Char], replace:Char, replacement:Char, result:List[Char] = Nil):List[Char] = arr match {
case `replace` :: tail =>
update(tail, replace, replacement, replacement :: result)
case _ => result.reverse ::: arr
}
This takes one of the inner sequences (assuming a List for easier pattern matching, since Arrays are trivially convertible to lists), and replaces the replace char with the replacement recursively.
You can then use map to update the outer sequence, like so:
col.map { x => update(x, '.', ch) }
Another more reusable alternative is writing your own mapUntil, or using one which is implemented in a supplemental library (Scalaz probably has something like it). The one I came up with looks like this:
def mapUntil[T](input:List[T])(f:(T => Option[T])) = {
#tailrec
def inner(xs:List[T], result:List[T]):List[T] = xs match {
case Nil => Nil
case head :: tail => f(head) match {
case None => (head :: result).reverse ::: tail
case Some(x) => inner(tail, x :: result)
}
}
inner(input, Nil)
}
It does the same as a regular map invocation, except that it stops as soon as the passed function returns None, e.g.
mapUntil(List(1,2,3,4)) {
case x if x >= 3 => None
case x => Some(x-1)
}
Will result in
List[Int] = List(0, 1, 3, 4)
If you want to look at Scalaz, this answer might be a good place to start.
x3ro's answer is the right answer, esp. if you care about performance or are going to be using this operation in multiple places. I would like to add simple solution using only what you find in the collections API:
col.map { a =>
val (l, r) = a.span(_ == '.')
l.map {
case '.' => ch
case x => x
} ++ r
}

Break or shortcircuit a fold in Scala

I have written a simple depth-first search in Scala with a recursive function like that:
search(labyrinth, path, goal)
where labyrinth is a specification of the problem (as graph or whatever), path is a list that holds the path taken so far and goal is a specification of the goal state. The function returns a path to the goal as a List and Nil if no path can be found.
The function expands, e.g. finds all suitable next nodes (candidates) and then has to recursively call itself.
I do this by
candidates.foldLeft(Nil){
(solution, next) =>
if( solution == Nil )
search( labyrinth, next :: path, goal )
else
solution
}
Please note that I have omitted some unescessary details. Everything is working fine so far. But once a solution is found inside the foldLeft call, this solution gets simply copied by the else part of the if-statement. Is there a way to avoid this by breaking the foldLeft or maybe by using a different function instead of foldLeft? Actually I could probably write a version of foldLeft which breaks once "not Nil" is returned myself. But is there one inside the API?
I'm not sure I understand the desire to short-circuit the loop. Is it expensive to iterate through the candidates? Is the candidates list potentially large?
Maybe you could use the "find" method:
candidates.find { c =>
Nil != search( labyrinth, c :: path, goal )
} match {
case Some(c) => c :: path
case None => Nil
}
If the potential depth of the search space is large, you could overflow your stack (fitting, given this site name). But, that is a topic for another post.
For giggles, here is an actual runnable implementation. I had to introduce a local mutable variable (fullPath) mostly out of laziness, but I'm sure you could take those out.
object App extends Application {
// This impl searches for a specific factor in a large int
type SolutionNode = Int
case class SearchDomain(number: Int) {
def childNodes(l: List[Int]): List[Int] = {
val num = if (l.isEmpty) number else l.head
if (num > 2) {
(2 to (num - 1)) find {
n => (num % n)==0
} match {
case Some(i) => List(i, num / i)
case None => List()
}
}
else List()
}
}
type DesiredResult = Int
def search ( labyrinth: SearchDomain, path: List[SolutionNode], goal: DesiredResult ): List[SolutionNode] = {
if ( !path.isEmpty && path.head == goal ) return path
if ( path.isEmpty ) return search(labyrinth, List(labyrinth.number), goal)
val candidates: List[SolutionNode] = labyrinth.childNodes(path)
var fullPath: List[SolutionNode] = List()
candidates.find { c =>
fullPath = search( labyrinth, c :: path, goal )
!fullPath.isEmpty
} match {
case Some(c) => fullPath
case None => Nil
}
}
// Is 5 a factor of 800000000?
val res = search(SearchDomain(800000000), Nil, 5)
println(res)
}
I like Mitch Blevins solution, as it is a perfect match for your algorithm. You may be interested in my own solution to another maze problem.
Ok so there are a lot of interpretations here, your question lacks some degrees of specificity.
I will try to point out all assumptions as I go along.
Existing Function: (First assumptions: Type signatures)
type Labyrinth // Not particularly important to logic
type Position // The grid "position" of the path
def search(labyrinth: Labyrinth, path: List[Position], goal: Position): List[Position]
The function expands, e.g. finds all suitable next nodes (candidates) and then has to recursively call itself.
Assumption: the following code is within the search function
def search(labyrinth: Labyrinth, path: List[Position], goal: Position): List[Position] = {
...
return candidates.foldLeft(Nil){
(solution, next) =>
if( solution == Nil )
search( labyrinth, next :: path, goal )
else
solution
}
}
Please note that I have omitted some unescessary details.
If my assumptions have been correct, then perhaps, but I still had to deduce some things.
Never assume the necessity of implementation details when asking for assistance on implementation, specificity makes answering questions far simpler.
Is there a way to avoid this by breaking the foldLeft or maybe by using a different function instead of foldLeft?
Why not use recursion?
def search(labyrinth: Labyrinth, path: List[Position], goal: Position): List[Position] = {
...
val candidates: List[Position] = ... // However you calculate those
def resultPathOpt(candidates: List[position]): Option[List[Position]] = {
candidates match {
// No candidates
case Nil => None
// At least one candidate
case firstCandidate :: restOfCandidates => {
// Search
search(labyrinth, firstCandidate :: path, goal) match {
// Search didn't pan out, no more candidates, done
case Nil if restOfCandidates.isEmpty => None
// Search didn't pan out, try other candidates
case Nil => resultPathOpt(restOfCandidates)
// Search panned out, done
case validPath => Some(validPath)
}
}
}
val maybeValidResult: Option[List[Position]] = resultPathOpt(candidates)
maybeValidResult.getOrElse(List.empty)
}
Now as soon as we find a "valid" path, note there is no check for this in the logic I have provided, so I am not quite sure if this would ever end as you have implemented it and as I have implemented this, but the concepts are still valid.