Skip to content

Instantly share code, notes, and snippets.

@gabro
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gabro/a45bebbdd1a86f40005b to your computer and use it in GitHub Desktop.
Save gabro/a45bebbdd1a86f40005b to your computer and use it in GitHub Desktop.
Automatic get parameters generator from case class for spray routing
package example
import scala.language.existentials
import shapeless._; import record._; import ops.record._; import ops.hlist._
import spray.routing.SimpleRoutingApp
trait AutoGetParametersModule { self: SimpleRoutingApp =>
import spray.routing.{ Directive, Directive1, Directive0, HListDeserializer }
import spray.routing.directives._
// mimic partial inference
trait AsBuilder[L <: HList] {
def apply[A](ds: HListDeserializer[L, A]): Directive1[A]
}
// mimic partial inference
class ParamsBuilder[A] {
def apply[Repr <: HList, O <: HList, L <: HList](implicit
lgen: LabelledGeneric.Aux[A, Repr],
names: Names.Aux[Repr, O],
folder: LeftFolder.Aux[O, Directive0, ParamDefMagnet2.MapReduce.type, Directive[L]]
): AsBuilder[L] = new AsBuilder[L] {
def apply[A](ds: HListDeserializer[L, A]) =
parameters(names.apply).as(ds)
}
}
def params[A] = new ParamsBuilder[A]
/* type class for building an HList of NameReceptacle from a LabelledGeneric */
trait Names[L <: HList] extends DepFn0 { type Out <: HList }
object Names {
def apply[L <: HList](implicit names: Names[L]): Aux[L, names.Out] = names
type Aux[L <: HList, Out0 <: HList] = Names[L] { type Out = Out0 }
implicit def hnilNames[L <: HNil]: Aux[L, HNil] =
new Names[L] {
type Out = HNil
def apply(): Out = HNil
}
implicit def hlistNames[K <: Symbol, V, T <: HList](implicit wk: Witness.Aux[K], nt: Names[T]): Aux[FieldType[K, V] :: T, NameReceptacle[V] :: nt.Out] =
new Names[FieldType[K, V] :: T] {
type Out = NameReceptacle[V] :: nt.Out
def apply(): Out = {
NameReceptacle[V](wk.value.name) :: nt()
}
}
}
}
object Main extends App with SimpleRoutingApp with AutoGetParametersModule {
implicit val system = akka.actor.ActorSystem("foo")
case class Foo(x: Option[String], y: Option[Boolean])
val fooParams = params[Foo].apply
startServer(interface = "localhost", port = 8080) {
path("foo") {
fooParams(Foo) { foo =>
complete(foo.toString)
}
}
}
}
@gabro
Copy link
Author

gabro commented Dec 12, 2014

Test with

curl http://127.0.0.1:8080/foo?x=foo&y=true

produces

Foo(Some(foo),Some(true))

@gabro
Copy link
Author

gabro commented Dec 13, 2014

also, Option fields in the case class, can be left out

curl http://127.0.0.1:8080/foo?x=foo

produces

Foo(Some(foo), None)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment