0

I'm looking for some way of converting a function which takes basic parameter types and using it to process an akka HttpRequest. I want the Path to be automatically processed and passed to the function.

As an example, given some function

def foobar(str : String, i : Int, l : Long) : String = ???

It would be useful to have a way of "lifting" the function to process a Path. An example URL Path could be

/foobar/einstein/42/2016

The lifting function would look something like:

import akka.http.scaladsl.model.Uri.Path
import akka.http.scaladsl.server.Directive

type SomeFunctionType = ???

def lifter(function : SomeFunctionType, path : Path) : Directive = {

  val funcResult = ??? //somehow call function on the Path elements

  complete(funcResult)
}

Which could then be used in the following way:

val route = 
  get {
    pathPrefix("foobar") {
      extractUnmatchedPath { remainingPath =>
        lifter(foobar, remainingPath)
      }
    }
  }

This lifting function would have to loop through the function parameter types and convert the corresponding Path section to the matching type before the values are passed into the function. The example URL would be completed with the result of the call foobar("enstein", 42, 2016).

Is there anyway to do this in the libraries? If not, is there a way to define lifter?

Thank you in advance for your consideration and response.

Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125
  • I guess the idiomatic way of doing it, would be adding the 3 different path directives to match against a String, Int and Long and then call the function with it. You can always create a custom directive that extracts those 3 types and then calls a function with these values – Josep Prat Oct 11 '16 at 08:04

1 Answers1

1

You seem to want to create a Route rather than a Directive. The difference is that a Route actually handles a request while a Directive wraps a route with more functionality. You seem to want to finally handle a request, so it should be a Route.

You seem to look for a very generic solution that would work for every function. This is currently only very hard (or even impossible) to do not least because you somehow need to specify how parameters should be parsed. spray-routing / akka-http routes actually somewhat discourage such a style in favor of a more explicit way of doing things.

E.g. given your given function definition of (String, Int, Long) => Route, the route would look like this:

def foobar(str: String, i: Int, l: Long): Route = complete(s"$str : $i : $l") // example implementation

// usage
path("foobar" / Segment / IntNumber / LongNumber)(foobar)

If you cannot convert foobar to return a route you can also create a helper that converts the function like this:

def foobar(str: String, i: Int, l: Long): String = s"$str : $i : $l"

def fromStringFunc3[T1, T2, T3](f: (T1, T2, T3) ⇒ String): (T1, T2, T3) ⇒ Route =
(t1, t2, t3) ⇒ complete(f(t1, t2, t3))

// usage
path("foobar" / Segment / IntNumber / LongNumber)(fromStringFunc3(foobar))

You will have to recreate this function for all arities, though (or build something more flexible with shapeless which is an advanced exercise ;) ).

jrudolph
  • 8,307
  • 4
  • 32
  • 50