2016-02-25 10 views
1

Я хотел бы сделать разбор параметров в случае несимметричного разброса. Например:Анализ синтаксического анализа нечувствительности к строкам в маршрутизации спрей

val route: Route = { 
    (path("search") & get) { 
    parameters('pagesize.as[Int] ?, 'appId ?) { (pageSize, appId) => 
     ... 
    } 
    } 
} 

В этом маршруте, я хотел бы параметры PAGESIZE и APPID работать при нечувствительной. Например, pagesize = 5 OR PAGESIZE = 5.

+3

вы можете создать настраиваемую директиву для использования вместо параметров. Я сейчас не на компьютере, но это не должно быть сложно, если посмотреть на реализацию параметров. –

ответ

1

Похоже, что получение параметров запроса из логики URI жестко закодировано в функции ParamDefMagnet2.filter.

Чтобы преодолеть это ограничение, я бы дублировал этот код, заменил логику ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName)) и импортировал ее при необходимости.

Пример использования будет выглядеть следующим образом:

import CaseInsensitiveQueryParameters._ 

val route: Route = { 
    (path("search") & get) { 
    parameters('pagesize.as[Int] ?, 'appId ?) { (pageSize, appId) => 
     ... 
    } 
    } 
} 

и переменил implicits будет выглядеть следующим образом:

object CaseInsensitiveQueryParameters { 
    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) } 

    import spray.httpx.unmarshalling.{ FromStringOptionDeserializer ⇒ FSOD, _ } 
    import BasicDirectives._ 
    import RouteDirectives._ 

    /************ "regular" parameter extraction ******************/ 

    private def extractParameter[A, B](f: A ⇒ Directive1[B]) = ParamDefMagnetAux[A, Directive1[B]](f) 
    private def filter[T](paramName: String, fsod: FSOD[T]): Directive1[T] = 
    extract(ctx ⇒ fsod(ctx.request.uri.query.find(_._1.equalsIgnoreCase(paramName)))).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) 
    } 
    implicit def forString(implicit fsod: FSOD[String]) = extractParameter[String, String] { string ⇒ 
    filter(string, fsod) 
    } 
    implicit def forSymbol(implicit fsod: FSOD[String]) = extractParameter[Symbol, String] { symbol ⇒ 
    filter(symbol.name, fsod) 
    } 
    implicit def forNDesR[T] = extractParameter[NameDeserializerReceptacle[T], T] { nr ⇒ 
    filter(nr.name, nr.deserializer) 
    } 
    implicit def forNDefR[T](implicit fsod: FSOD[T]) = extractParameter[NameDefaultReceptacle[T], T] { nr ⇒ 
    filter(nr.name, fsod.withDefaultValue(nr.default)) 
    } 
    implicit def forNDesDefR[T] = extractParameter[NameDeserializerDefaultReceptacle[T], T] { nr ⇒ 
    filter(nr.name, nr.deserializer.withDefaultValue(nr.default)) 
    } 
    implicit def forNR[T](implicit fsod: FSOD[T]) = extractParameter[NameReceptacle[T], T] { nr ⇒ 
    filter(nr.name, fsod) 
    } 
} 
2

Я принял ответ Мустафы один шаг дальше и расширенный синтаксис параметров, так что вы можете использовать не - чувствительные к регистру параметры вместе с чувствительностью к регистру (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 и получить оттуда параметры.