Permalink
Fetching contributors…
Cannot retrieve contributors at this time
148 lines (121 sloc) 5.76 KB
/*
* Copyright © 2011-2015 the spray project <http://spray.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package spray.routing
package directives
import shapeless._
trait ParameterDirectives extends ToNameReceptaclePimps {
/**
* Extracts the requests query parameters as a Map[String, String].
*/
def parameterMap: Directive[Map[String, String] :: HNil] = ParameterDirectives._parameterMap
/**
* Extracts the requests query parameters as a Map[String, List[String]].
*/
def parameterMultiMap: Directive[Map[String, List[String]] :: HNil] = ParameterDirectives._parameterMultiMap
/**
* Extracts the requests query parameters as a Seq[(String, String)].
*/
def parameterSeq: Directive[Seq[(String, String)] :: HNil] = ParameterDirectives._parameterSeq
/**
* Rejects the request if the query parameter matcher(s) defined by the definition(s) don't match.
* Otherwise the parameter value(s) are extracted and passed to the inner route.
*/
/* directive */ def parameter(pdm: ParamDefMagnet): pdm.Out = pdm()
/**
* Rejects the request if the query parameter matcher(s) defined by the definition(s) don't match.
* Otherwise the parameter value(s) are extracted and passed to the inner route.
*/
/* directive */ def parameters(pdm: ParamDefMagnet): pdm.Out = pdm()
}
object ParameterDirectives extends ParameterDirectives {
import BasicDirectives._
private val _parameterMap: Directive[Map[String, String] :: HNil] =
extract(_.request.uri.query.toMap)
private val _parameterMultiMap: Directive[Map[String, List[String]] :: HNil] =
extract(_.request.uri.query.toMultiMap)
private val _parameterSeq: Directive[Seq[(String, String)] :: HNil] =
extract(_.request.uri.query.toSeq)
}
trait ParamDefMagnet {
type Out
def apply(): Out
}
object ParamDefMagnet {
implicit def apply[T](value: T)(implicit pdm2: ParamDefMagnet2[T]) = new ParamDefMagnet {
type Out = pdm2.Out
def apply() = pdm2(value)
}
}
trait ParamDefMagnet2[T] {
type Out
def apply(value: T): Out
}
object ParamDefMagnet2 {
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.get(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)
}
/************ required parameter support ******************/
private def requiredFilter(paramName: String, fsod: FSOD[_], requiredValue: Any): Directive0 =
extract(ctx fsod(ctx.request.uri.query.get(paramName))).flatMap {
case Right(value) if value == requiredValue pass
case _ reject
}
implicit def forRVR[T](implicit fsod: FSOD[T]) = ParamDefMagnetAux[RequiredValueReceptacle[T], Directive0] { rvr
requiredFilter(rvr.name, fsod, rvr.requiredValue)
}
implicit def forRVDR[T] = ParamDefMagnetAux[RequiredValueDeserializerReceptacle[T], Directive0] { rvr
requiredFilter(rvr.name, rvr.deserializer, rvr.requiredValue)
}
/************ tuple support ******************/
implicit def forTuple[T <: Product, L <: HList, Out0](implicit hla: HListerAux[T, L], pdma: ParamDefMagnetAux[L, Out0]) =
ParamDefMagnetAux[T, Out0](tuple pdma(hla(tuple)))
/************ HList support ******************/
implicit def forHList[L <: HList](implicit f: LeftFolder[L, Directive0, MapReduce.type]) =
ParamDefMagnetAux[L, f.Out](_.foldLeft(BasicDirectives.noop)(MapReduce))
object MapReduce extends Poly2 {
implicit def from[T, LA <: HList, LB <: HList, Out <: HList](implicit pdma: ParamDefMagnetAux[T, Directive[LB]], ev: PrependAux[LA, LB, Out]) =
at[Directive[LA], T] { (a, t) a & pdma(t) }
}
}