I developed custom generic directive, which will provide param of given type, if it exists, or else reject with my custom exception.
import akka.http.scaladsl.common.NameReceptacle
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.directives.ParameterDirectives.ParamDefAux
import akka.http.scaladsl.server.{Directive1, Route}
class MyCustomException(msg: String) extends Exception(msg)
def requireParam[T](name: NameReceptacle[T])
(implicit pdef: ParamDefAux[NameReceptacle[T], Directive1[T]]): Directive1[T] =
parameter(name).recover { _ =>
throw new MyCustomException(s"${name.name} is missed!")
}
It works ok, if I want to create route, using two parameters, for example:
val negSumParams: Route =
(requireParam("param1".as[Int]) & requireParam("param2".as[Int])) {
(param1, param2) =>
complete((-param1-param2).toString)
}
But if I try to use exactly one parameter, this doesn't compile:
val negParamCompilationFail: Route =
requireParam("param".as[Int]) {
param => // scalac complains about missing type param here
complete((-param).toString)
}
If I use it with pass directive, it works:
val negParamWithPass: Route =
(pass & requireParam("param".as[Int])) { // this pass usage looks hacky
param =>
complete((-param).toString)
}
If I write requireParam() return type explicitly, it works too:
val negParamWithExplicitType: Route =
(requireParam("param".as[Int]): Directive1[Int]) { // DRY violation
param =>
complete((-param).toString)
}
Why do I need these tricks? Why can't it work just with requireParam("param".as[Int])?
Scala version 2.12.1, Akka-HTTP 10.0.10.
This error happens due to the Directive companion object apply method. IT allows to create a Route from a function with parameter (T => Route) => Route:
object Directive {
/**
* Constructs a directive from a function literal.
*/
def apply[T: Tuple](f: (T ⇒ Route) ⇒ Route): Directive[T] =
new Directive[T] { def tapply(inner: T ⇒ Route) = f(inner) }
}
But the T parameter must be a tuple. In your case, the compiler can not build the Route. Your requireParam("param".as[Int]) returns a Directive1[Int] so the apply method doesn´t work because Int is not a Tuple.
To make this work you shoul use tapply method directly:
(requireParam("param1".as[Int])).tapply((param1) =>
complete((-param1._1).toString))
and
val negSumParams2: Route =
(requireParam("param1".as[Int]) & requireParam("param2".as[Int])).tapply {
case (param1, param2) =>
complete((-param1-param2).toString)
}
So it seems that every Directive tries to convert its param to TupleX. For example:
path("order" / IntNumber) returns a Directive[Tuple1[Int]] instead of Directive1[Int]. In your case requireParam("param1".as[Int]) returns Directive1[Int]
Maybe there is a better solution and to avoid tapply
Johannes from Lightbend answered to this question here: https://groups.google.com/forum/#!topic/akka-user/NmQvcrz5sJg Answer is:
You discovered one of the reasons for the magnet pattern. If you use
requireParam("param".as[Int]) { abc => ... } then the { abc => }
block is mistaken as the implicit argument of requireParam. So,
either you are ok with that and require users to use extra parentheses
((requireParam("param".as[Int])) { abc => ... }) or you use the
magnet pattern at this level as well. You can read about the magnet
pattern on the old spray blog
(http://spray.io/blog/2012-12-13-the-magnet-pattern/) or just look
into akka-http sources.
A better way to implement the feature would be just to use the
existing implementation ;) and install a custom rejection handler that
produces whatever output you would like. See
https://doc.akka.io/docs/akka-http/10.0.10/scala/http/routing-dsl/rejections.html#customizing-rejection-handling
for how to do that.
Related
I've got an API that looks like this:
object Comics {
...
def impl[F[_]: Applicative]: Comics[F] = new Comics[F] {
def getAuthor(slug: Authors.Slug): F[Option[Authors.Author]] =
...
and a routing that looks like this:
object Routes {
def comicsRoutes[F[_]: Sync](comics: Comics[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._
HttpRoutes.of[F] {
case GET -> Root / "comics" / authorSlug =>
comics
.getAuthor(Authors.Slug(authorSlug))
.flatMap {
case Some(author) => Ok(author)
case None => NotFound()
}
So when there is a None, it gets converted to a 404. Since there are several routes, the .flatMap { ... } gets duplicated.
Question: How do I move this into a separate .orNotFound helper function specific to my project?
My attempt:
To make things simple for me (and avoid parameterisation over F initially), I've tried to define this inside comicsRoutes:
def comicsRoutes[F[_]: Sync](comics: Comics[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._
def orNotFound[A](opt: Option[A]): ???[A] =
opt match {
case Some(value) => Ok(value)
case None => NotFound()
}
HttpRoutes.of[F] {
case GET -> Root / "comics" / authorSlug =>
comics
.getAuthor(Authors.Slug(authorSlug))
.flatMap(orNotFound)
But what's ??? here? It doesn't seem to be Response or Status. Also, the .flatMap { ... } was made under import dsl._, but I'd like to move this further out. What would a good place be? Does it go into the routes file, or do I put it in a separate ExtendedSomething extension file? (I expect that ??? and Something might be related, but I'm a little confused as to what the missing types are.)
(Equally importantly, how do I find out what ??? is here? I was hoping ??? at the type level might give me a "typed hole", and VSCode's hover function provides very sporadic documentation value.)
The type returned by Http4sDsl[F] for your actions is F[Response[F]].
It has to be wrapped with F because your are using .flatMap on F. Response is parametrized with F because it will produce the result returned to caller using F.
To find that out you can use IntelliJ and then generate the annotation by IDE (Alt+Enter and then "Add type annotation to value definition"). You can also:
preview implicits to check that Ok object imported from Statuses trait is provided extension methods with http4sOkSyntax implicit conversion (Ctrl+Alt+Shift+Plus sign, you can press it a few times to expand implicits more, and Ctrl+Alt+Shift+Minut to hide them again)
find http4sOkSyntax by pressing Shift twice to open find window, and then pressing it twice again to include non-project symbols,
from there navigate with Ctrl+B through OkOps to EntityResponseGenerator class which is providing you the
functionality you used (in apply) returning F[Resposne[F]].
So if you want to move things around/extract them, pay attention to what implicits are required to instantiate the DSL and extension methods.
(Shortcuts differ between Mac OS - which sometime use Cmd instead of Ctrl - and non-Mac OS systems so just check them in documentation if you have an issue).
Thanks to Mateusz, I learned that ??? should be F[Response[F]].
To make this helper function work fully, two more type-related problems occurred:
Since value: A is polymorphic, Http4s expects an implicit EntityEncoder[F, A] in order to serialize an arbitrary value. (This was not a problem with the original { case ... } match, since the type was concrete and not polymorphic.
Adding this implicit annotation was, for some reason, not enough. Doing .flatMap(orNotFound) fails type inference. Doing .flatMap(orNotFound[Authors.Slug]) fixes this.
(Thanks to keynmol for pointing out the other two.)
Having all three changes, this results in:
def comicsRoutes[F[_]: Sync](comics: Comics[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F] {}
import dsl._
def orNotFound[A](opt: Option[A])(implicit ee: EntityEncoder[F, A]): F[Response[F]] =
opt match {
case Some(value) => Ok(value)
case None => NotFound()
}
HttpRoutes.of[F] {
case GET -> Root / "comics" / authorSlug =>
comics
.getAuthor(Authors.Slug(authorSlug))
.flatMap(orNotFound[Authors.Author])
...
This is more of a Scala question but inspired by this http-scala example.
val route =
path("hello") {
get {
complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>"))
}
}
Based on example path seems like it could be a curried method that takes String as first argument and Route as second although I do not see such implementation in the API. Could someone enlighten me how this works?
Link to docs: http://doc.akka.io/api/akka-http/current/akka/http/javadsl/server/Directives$.html#path(segment:String,inner:java.util.function.Supplier[akka.http.javadsl.server.Route]):akka.http.javadsl.server.Route
No, path is not a curried function. The API gives the signature:
def path[L](pm: PathMatcher[L]): Directive[L]
Path is a simple unary function that takes in a PathMatcher and returns a Directive. Path only seems like it is a curried function because Directive has an apply method which makes it appear to be a function, but it's actually a class.
PathMatcher
By importing Directives._ the following implicit function becomes available:
implicit def _segmentStringToPathMatcher(segment: String): PathMatcher0
Note: PathMatcher0 is defined as PathMatcher[Unit] since it does not pass the matched value along to the inner Route.
Calling path with the argument in the example, path("hello"), is similar to following code:
val directive : Directive[Unit] = path(_segmentStringToPathMatcher("hello"))
Directive
As stated previously, the Directive has an apply method that lazily takes in a Route:
def apply(v1 : => Route) : Route
So your example code is essentially making the following call:
val route =
directive.apply(get {
complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>"))
})
Putting It All Together
Let's simplify the definition of Route and mock some logic to demonstrate what is happening:
type SimpleRoute : HttpRequest => RouteResult
We can now write a version of path using a higher order function. Our simpler version takes in a String and returns a function instead of a Directive. It gets a little tricky because the returned function is also higher order:
def simplePath(pathStr : String) : SimpleRoute => SimpleRoute =
(innerRoute : SimpleRoute) => {
//this is the returned SimpleRoute
(request : HttpRequest) => {
if(request.uri.path.toString equalsIgnoreCase pathStr)
RouteResult.Complete(innerRoute(request))
else
RouteResult.Rejected(Seq.empty[Rejection])
}
}
What is still unclear for is what's the advantage by-name parameters over anonymous functions in terms of lazy evaluation and other benefits if any:
def func1(a: => Int)
def func2(a: () => Int)
When should I use the first and when the second one?
This is not the copy of What's the difference between => , ()=>, and Unit=>
Laziness is the same in the both cases, but there are slight differences. Consider:
def generateInt(): Int = { ... }
def byFunc(a: () => Int) { ... }
def byName(a: => Int) { ... }
// you can pass method without
// generating additional anonymous function
byFunc(generateInt)
// but both of the below are the same
// i.e. additional anonymous function is generated
byName(generateInt)
byName(() => generateInt())
Functions with call-by-name however is useful for making DSLs. For instance:
def measured(block: ⇒ Unit): Long = {
val startTime = System.currentTimeMillis()
block
System.currentTimeMillis() - startTime
}
Long timeTaken = measured {
// any code here you like to measure
// written just as there were no "measured" around
}
def func1(a: => Int) {
val b = a // b is of type Int, and it`s value is the result of evaluation of a
}
def func2(a: () => Int) {
val b = a // b is of type Function0 (is a reference to function a)
}
An example might give a pretty thorough tour of the differences.
Consider that you wanted to write your own version of the veritable while loop in Scala. I know, I know... using while in Scala? But this isn't about functional programming, this is an example that demonstrates the topic well. So hang with me. We'll call our own version whyle. Furthermore, we want to implement it without using Scala's builtin while. To pull that off we can make our whyle construct recursive. Also, we'll add the #tailrec annotation to make sure that our implementation can be used as a real-world substitute for the built-in while. Here's a first go at it:
#scala.annotation.tailrec
def whyle(predicate: () => Boolean)(block: () => Unit): Unit = {
if (predicate()) {
block()
whyle(predicate)(block)
}
}
Let's see how this works. We can pass in parameterized code blocks to whyle. The first is the predicate parameterized function. The second is the block parameterized function. How would we use this?
What we want is for our end user to use the whyle just like you would the while control structure:
// Using the vanilla 'while'
var i = 0
while(i < args.length) {
println(args(i))
i += 1
}
But since our code blocks are parameterized, the end-user of our whyle loop must add some ugly syntactic sugar to get it to work:
// Ouch, our whyle is hideous
var i = 0
whyle( () => i < args.length) { () =>
println(args(i))
i += 1
}
So. It appears that if we want the end-user to be able to call our whyle loop in a more familiar, native looking style, we'll need to use parameterless functions. But then we have a really big problem. As soon as you use parameterless functions, you can no longer have your cake and eat it too. You can only eat your cake. Behold:
#scala.annotation.tailrec
def whyle(predicate: => Boolean)(block: => Unit): Unit = {
if (predicate) {
block
whyle(predicate)(block) // !!! THIS DOESN'T WORK LIKE YOU THINK !!!
}
}
Wow. Now the user can call our whyle loop the way they expect... but our implementation doesn't make any sense. You have no way of both calling a parameterless function and passing the function itself around as a value. You can only call it. That's what I mean by only eating your cake. You can't have it, too. And therefore our recursive implementation now goes out the window. It only works with the parameterized functions which is unfortunately pretty ugly.
We might be tempted at this point to cheat. We could rewrite our whyle loop to use Scala's built-in while:
def whyle(pred: => Boolean)(block: => Unit): Unit = while(pred)(block)
Now we can use our whyle exactly like while, because we only needed to be able to eat our cake... we didn't need to have it, too.
var i = 0
whyle(i < args.length) {
println(args(i))
i += 1
}
But we cheated! Actually, here's a way to have our very own tail-optimized version of the while loop:
def whyle(predicate: => Boolean)(block: => Unit): Unit = {
#tailrec
def whyle_internal(predicate2: () => Boolean)(block2: () => Unit): Unit = {
if (predicate2()) {
block2()
whyle_internal(predicate2)(block2)
}
}
whyle_internal(predicate _)(block _)
}
Can you figure out what we just did?? We have our original (but ugly) parameterized functions in the inner function here. We have it wrapped with a function that takes as arguments parameterless functions. It then calls the inner function and converts the parameterless functions into parameterized functions (by turning them into partially applied functions).
Let's try it out and see if it works:
var i = 0
whyle(i < args.length) {
println(args(i))
i += 1
}
And it does!
Thankfully, since in Scala we have closures we can clean this up big time:
def whyle(predicate: => Boolean)(block: => Unit): Unit = {
#tailrec
def whyle_internal: Unit = {
if (predicate) {
block
whyle_internal
}
}
whyle_internal
}
Cool. Anyways, those are some really big differences between parameterless and parameterized functions. I hope this gives you some ideas!
The two formats are used interchangeably, but there are some cases where we can use only one of theme.
let's explain by example, suppose that we need to define a case class with two parameters :
{
.
.
.
type Action = () => Unit;
case class WorkItem(time : Int, action : Action);
.
.
.
}
as we can see, the second parametre of the WorkItem class has a type Action.
if we try to replace this parameter with the other format =>,
case class WorkItem1(time : Int, s : => Unit) the compiler will show a message error :
Multiple markers at this line:
`val' parameters may not be call-by-name Call-by-name parameter
creation: () ⇒
so as we have see the format ()=> is more generic and we can use it to define Type, as class field or method parameter, in the other side => format can used as method parameter but not as class field.
A by-name type, in which the empty parameter list, (), is left out, is only
allowed for parameters. There is no such thing as a by-name variable or a
by-name field.
You should use the first function definition if you want to pass as the argument an Int by name.
Use the second definition if you want the argument to be a parameterless function returning an Int.
Scala noob here.
I'm trying to apply a map in a class method:
class Miner(args: Args) extends Job(args) {
def fetchUrl(url:String) = {
...
}
TextLine(args("input")).map(url: String => fetchUrl(url))
.write(args("output"))
}
this codes breaks complaining about not being able to resolve the symbol fetchUrl.
I've thought that, fetchUrl being a one argument function, I could just omit the argument and do something like:
TextLine(args("input")).map(fetchUrl)
.write(args("output"))
This now breaks saying that I'm missing arguments for the method fetchUrl.
What gives?
Isn't mapTo a curried function?
I imagine you use this function from this object: (google redirects me to that)
mapTo[U](out: Fields)(mf: (String) ⇒ U)(implicit flowDef: FlowDef, mode: Mode, setter: TupleSetter[U]): Pipe
Perhaps you would use it like this: Textline.mapTo(args("input"))(fetchUrl)
You have some examples of mapTo usage at this page, but based on the Pipe object:
https://github.com/twitter/scalding/wiki/Fields-based-API-Reference#map-functions
Excerpt:
val savings =
items.mapTo(('price, 'discountedPrice) -> 'savings) {
x : (Float, Float) =>
val (price, discountedPrice) = x
price - discountedPrice
}
So not based on TextLine in this example, but also curried...this might be a good hint for you.
I try to feel the advantage of implicit parameters in Scala. (EDITED: special case when anonymous function is used. Please look at the links in this question)
I try to make simple emulation based on this post. Where explained how Action works in PlayFramework. This also related to that.
The following code is for that purpose:
object ImplicitArguments extends App {
implicit val intValue = 1 // this is exiting value to be passed implicitly to everyone who might use it
def fun(block: Int=>String): String = { // we do not use _implicit_ here !
block(2) // ?? how to avoid passing '2' but make use of that would be passed implicitly ?
}
// here we use _implicit_ keyword to make it know that the value should be passed !
val result = fun{ implicit intValue => { // this is my 'block'
intValue.toString // (which is anonymous function)
}
}
println(result) // prints 2
}
I want to get "1" printed.
How to avoid passing magic "2" but use "1" that was defined implicitly?
Also see the case where we do not use implicit in definition, but it is there, because of anonymous function passing with implicit.
EDITED:
Just in case, I'm posting another example - simple emulation of how Play' Action works:
object ImplicitArguments extends App {
case class Request(msg:String)
implicit val request = Request("my request")
case class Result(msg:String)
case class Action(result:Result)
object Action {
def apply(block:Request => Result):Action = {
val result = block(...) // what should be here ??
new Action(result)
}
}
val action = Action { implicit request =>
Result("Got request [" + request + "]")
}
println(action)
}
Implicits don't work like this. There is no magic. They are just (usually) hidden parameters and are therefore resolved when invoking the function.
There are two ways to make your code work.
you can fix the implicit value for all invocations of fun
def fun(block: Int=>String): String = {
block(implicitly[Int])
}
implicitly is a function defined in Predef. Again no magic. Here's it's definition
def implicitly[A](implicit value: A) = value
But this means it will resolve the implicit value when declaring the fun and not for each invocation.
If you want to use different values for different invocations you will need to add the implicit paramter
def fun(block: Int=>String)(implicit value: Int): String = {
block(value)
}
This will now depend on the implicit scope at the call site. And you can easily override it like this
val result = fun{ _.toString }(3)
and result will be "3" because of the explicit 3 at the end. There is, however, no way to magically change the fun from your declaration to fetch values from implicit scope.
I hope you understand implicits better now, they can be a bit tricky to wrap your head around at first.
It seems that for that particular case I asked, the answer might be like this:
That this is not really a good idea to use implicit intValue or implicit request along with implicitly() using only one parameter for the function that accept (anonymous) function.
Why not, because:
Say, if in block(...) in apply() I would use implicitly[Request], then
it does not matter whether I use "implicit request" or not - it will use
request that is defined implicitly somewhere. Even if I would pass my
own request to Action { myOwnRequest =Result }.
For that particular case is better to use currying and two arguments and.. in the second argument - (first)(second) to use implicit
Like this:
def apply(block:Request => Result)(implicit request:Request):Action2
See my little effort around this example/use case here.
But, I don't see any good example so far in regards to how to use implicit by passing the (anonymous) function as argument (my initial question):
fun{ implicit intValue => {intValue.toString}
or that one (updated version):
val action = Action { implicit request =>
Result("Got request [" + request + "]")
}