Я принял ответ Мустафы один шаг дальше и расширенный синтаксис параметров, так что вы можете использовать не - чувствительные к регистру параметры вместе с чувствительностью к регистру (Big Hooray для моделей и моделей магнитов!):
package caseinsensitive
import spray.routing.SimpleRoutingApp
import akka.actor.ActorSystem
import spray.routing.directives.BasicDirectives
import spray.routing.directives.RouteDirectives
import scala.language.implicitConversions
/**/
import spray.httpx.unmarshalling.{ FromStringOptionDeserializer ⇒ FSOD, _}
trait ToCINameReceptaclePimps {
implicit def symbol2CINR(symbol: Symbol) = new CINameReceptacleHelper[String](symbol.name)
implicit def string2CINR(string: String) = new CINameReceptacleHelper[String](string)
}
case class CINameReceptacleHelper[T](name: String) {
def insensitive = CINameReceptacle[T](name)
}
case class CINameReceptacle[A](name: String) {
def as[B] = CINameReceptacle[B](name)
def as[B](deserializer: FSOD[B]) = CINameDeserializerReceptacle(name, deserializer)
def ? = as[Option[A]]
def ?[B](default: B) =CINameDefaultReceptacle(name, default)
def ![B](requiredValue: B) = CIRequiredValueReceptacle(name, requiredValue)
}
case class CINameDeserializerReceptacle[A](name: String, deserializer: FSOD[A]) {
def ? = CINameDeserializerReceptacle(name, Deserializer.liftToTargetOption(deserializer))
def ?(default: A) = CINameDeserializerDefaultReceptacle(name, deserializer, default)
def !(requiredValue: A) = CIRequiredValueDeserializerReceptacle(name, deserializer, requiredValue)
}
case class CINameDefaultReceptacle[A](name: String, default: A)
case class CIRequiredValueReceptacle[A](name: String, requiredValue: A)
case class CINameDeserializerDefaultReceptacle[A](name: String, deserializer: FSOD[A], default: A)
case class CIRequiredValueDeserializerReceptacle[A](name: String, deserializer: FSOD[A], requiredValue: A)
/**/
trait CaseInsensitiveParams extends ToCINameReceptaclePimps {
import spray.routing._
import spray.routing.directives._
import spray.httpx.unmarshalling.{ FromStringOptionDeserializer ⇒ FSOD, _ }
import BasicDirectives._
import RouteDirectives._
type ParamDefMagnetAux[A, B] = ParamDefMagnet2[A] { type Out = B }
def ParamDefMagnetAux[A, B](f: A ⇒ B) = new ParamDefMagnet2[A] { type Out = B; def apply(value: A) = f(value) }
private def extractParameter[A, B](f: A ⇒ Directive1[B]) = ParamDefMagnetAux[A, Directive1[B]](f)
private def filterCI[T](paramName: String, fsod: FSOD[T]): Directive1[T] =
extract(ctx ⇒ fsod(ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName)).map(_._2))).flatMap {
case Right(x) ⇒ provide(x)
case Left(ContentExpected) ⇒ reject(MissingQueryParamRejection(paramName))
case Left(MalformedContent(error, cause)) ⇒ reject(MalformedQueryParamRejection(paramName, error, cause))
case Left(x: UnsupportedContentType) ⇒ throw new IllegalStateException(x.toString)
}
/************ "regular" parameter extraction ******************/
implicit def forCINDesR[T] = extractParameter[CINameDeserializerReceptacle[T], T] { nr ⇒
filterCI(nr.name, nr.deserializer)
}
implicit def forCINDefR[T](implicit fsod: FSOD[T]) = extractParameter[CINameDefaultReceptacle[T], T] { nr ⇒
filterCI(nr.name, fsod.withDefaultValue(nr.default))
}
implicit def forCINDesDefR[T] = extractParameter[CINameDeserializerDefaultReceptacle[T], T] { nr ⇒
filterCI(nr.name, nr.deserializer.withDefaultValue(nr.default))
}
implicit def forCINR[T](implicit fsod: FSOD[T]) = extractParameter[CINameReceptacle[T], T] { nr ⇒
filterCI(nr.name, fsod)
}
/************ required parameter support ******************/
private def requiredFilterCI(paramName: String, fsod: FSOD[_], requiredValue: Any): Directive0 =
extract(ctx ⇒ fsod(ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName)).map(_._2))).flatMap {
case Right(value) if value == requiredValue ⇒ pass
case _ ⇒ reject
}
implicit def forCIRVR[T](implicit fsod: FSOD[T]) = ParamDefMagnetAux[CIRequiredValueReceptacle[T], Directive0] { rvr ⇒
requiredFilterCI(rvr.name, fsod, rvr.requiredValue)
}
implicit def forCIRVDR[T] = ParamDefMagnetAux[CIRequiredValueDeserializerReceptacle[T], Directive0] { rvr ⇒
requiredFilterCI(rvr.name, rvr.deserializer, rvr.requiredValue)
}
}
object Main extends App with SimpleRoutingApp with CaseInsensitiveParams {
implicit val system = ActorSystem("my-system")
startServer(interface = "localhost", port = 8080) {
path("hello") {
parameters("foo".insensitive.?) { foo =>
get {
complete {
<h1>You said {foo} </h1>
}
}
}
}
}
}
Если вам не нужно все это, вы можете просто использовать директиву parameterMap
и получить оттуда параметры.
вы можете создать настраиваемую директиву для использования вместо параметров. Я сейчас не на компьютере, но это не должно быть сложно, если посмотреть на реализацию параметров. –