htp #20103 introduce Scaladoc groups for Directives
This commit is contained in:
parent
f2771eaab9
commit
aec81c2ac2
28 changed files with 537 additions and 8 deletions
|
|
@ -42,4 +42,4 @@ class NameDefaultUnmarshallerReceptacle[T](val name: String, val default: T, val
|
||||||
|
|
||||||
class RequiredValueUnmarshallerReceptacle[T](val name: String, val requiredValue: T, val um: FSU[T])
|
class RequiredValueUnmarshallerReceptacle[T](val name: String, val requiredValue: T, val um: FSU[T])
|
||||||
|
|
||||||
class RepeatedValueUnmarshallerReceptacle[T](val name: String, val um: FSU[T])
|
class RepeatedValueUnmarshallerReceptacle[T](val name: String, val um: FSU[T])
|
||||||
|
|
|
||||||
|
|
@ -223,12 +223,18 @@ object PathMatcher extends ImplicitPathMatcherConstruction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname pathmatcherimpl Path matcher implicits
|
||||||
|
* @groupprio pathmatcherimpl 172
|
||||||
|
*/
|
||||||
trait ImplicitPathMatcherConstruction {
|
trait ImplicitPathMatcherConstruction {
|
||||||
import PathMatcher._
|
import PathMatcher._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a PathMatcher that consumes (a prefix of) the first path segment
|
* Creates a PathMatcher that consumes (a prefix of) the first path segment
|
||||||
* (if the path begins with a segment) and extracts a given value.
|
* (if the path begins with a segment) and extracts a given value.
|
||||||
|
*
|
||||||
|
* @group pathmatcherimpl
|
||||||
*/
|
*/
|
||||||
implicit def stringExtractionPair2PathMatcher[T](tuple: (String, T)): PathMatcher1[T] =
|
implicit def stringExtractionPair2PathMatcher[T](tuple: (String, T)): PathMatcher1[T] =
|
||||||
PathMatcher(tuple._1 :: Path.Empty, Tuple1(tuple._2))
|
PathMatcher(tuple._1 :: Path.Empty, Tuple1(tuple._2))
|
||||||
|
|
@ -236,10 +242,15 @@ trait ImplicitPathMatcherConstruction {
|
||||||
/**
|
/**
|
||||||
* Creates a PathMatcher that consumes (a prefix of) the first path segment
|
* Creates a PathMatcher that consumes (a prefix of) the first path segment
|
||||||
* (if the path begins with a segment).
|
* (if the path begins with a segment).
|
||||||
|
*
|
||||||
|
* @group pathmatcherimpl
|
||||||
*/
|
*/
|
||||||
implicit def segmentStringToPathMatcher(segment: String): PathMatcher0 =
|
implicit def segmentStringToPathMatcher(segment: String): PathMatcher0 =
|
||||||
PathMatcher(segment :: Path.Empty, ())
|
PathMatcher(segment :: Path.Empty, ())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group pathmatcherimpl
|
||||||
|
*/
|
||||||
implicit def stringNameOptionReceptacle2PathMatcher(nr: NameOptionReceptacle[String]): PathMatcher0 =
|
implicit def stringNameOptionReceptacle2PathMatcher(nr: NameOptionReceptacle[String]): PathMatcher0 =
|
||||||
PathMatcher(nr.name).?
|
PathMatcher(nr.name).?
|
||||||
|
|
||||||
|
|
@ -249,6 +260,8 @@ trait ImplicitPathMatcherConstruction {
|
||||||
* Extracts either the complete match (if the regex doesn't contain a capture group) or
|
* Extracts either the complete match (if the regex doesn't contain a capture group) or
|
||||||
* the capture group (if the regex contains exactly one).
|
* the capture group (if the regex contains exactly one).
|
||||||
* If the regex contains more than one capture group the method throws an IllegalArgumentException.
|
* If the regex contains more than one capture group the method throws an IllegalArgumentException.
|
||||||
|
*
|
||||||
|
* @group pathmatcherimpl
|
||||||
*/
|
*/
|
||||||
implicit def regex2PathMatcher(regex: Regex): PathMatcher1[String] = regex.groupCount match {
|
implicit def regex2PathMatcher(regex: Regex): PathMatcher1[String] = regex.groupCount match {
|
||||||
case 0 ⇒ new PathMatcher1[String] {
|
case 0 ⇒ new PathMatcher1[String] {
|
||||||
|
|
@ -276,18 +289,26 @@ trait ImplicitPathMatcherConstruction {
|
||||||
* Creates a PathMatcher from the given Map of path segments (prefixes) to extracted values.
|
* Creates a PathMatcher from the given Map of path segments (prefixes) to extracted values.
|
||||||
* If the unmatched path starts with a segment having one of the maps keys as a prefix
|
* If the unmatched path starts with a segment having one of the maps keys as a prefix
|
||||||
* the matcher consumes this path segment (prefix) and extracts the corresponding map value.
|
* the matcher consumes this path segment (prefix) and extracts the corresponding map value.
|
||||||
|
*
|
||||||
|
* @group pathmatcherimpl
|
||||||
*/
|
*/
|
||||||
implicit def valueMap2PathMatcher[T](valueMap: Map[String, T]): PathMatcher1[T] =
|
implicit def valueMap2PathMatcher[T](valueMap: Map[String, T]): PathMatcher1[T] =
|
||||||
if (valueMap.isEmpty) PathMatchers.nothingMatcher
|
if (valueMap.isEmpty) PathMatchers.nothingMatcher
|
||||||
else valueMap.map { case (prefix, value) ⇒ stringExtractionPair2PathMatcher((prefix, value)) }.reduceLeft(_ | _)
|
else valueMap.map { case (prefix, value) ⇒ stringExtractionPair2PathMatcher((prefix, value)) }.reduceLeft(_ | _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname pathmatcher Path matchers
|
||||||
|
* @groupprio pathmatcher 171
|
||||||
|
*/
|
||||||
trait PathMatchers {
|
trait PathMatchers {
|
||||||
import PathMatcher._
|
import PathMatcher._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a path string containing slashes into a PathMatcher that interprets slashes as
|
* Converts a path string containing slashes into a PathMatcher that interprets slashes as
|
||||||
* path segment separators.
|
* path segment separators.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
def separateOnSlashes(string: String): PathMatcher0 = {
|
def separateOnSlashes(string: String): PathMatcher0 = {
|
||||||
@tailrec def split(ix: Int = 0, matcher: PathMatcher0 = null): PathMatcher0 = {
|
@tailrec def split(ix: Int = 0, matcher: PathMatcher0 = null): PathMatcher0 = {
|
||||||
|
|
@ -301,6 +322,8 @@ trait PathMatchers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that matches a single slash character ('/').
|
* A PathMatcher that matches a single slash character ('/').
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object Slash extends PathMatcher0 {
|
object Slash extends PathMatcher0 {
|
||||||
def apply(path: Path) = path match {
|
def apply(path: Path) = path match {
|
||||||
|
|
@ -311,6 +334,8 @@ trait PathMatchers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that matches the very end of the requests URI path.
|
* A PathMatcher that matches the very end of the requests URI path.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object PathEnd extends PathMatcher0 {
|
object PathEnd extends PathMatcher0 {
|
||||||
def apply(path: Path) = path match {
|
def apply(path: Path) = path match {
|
||||||
|
|
@ -324,6 +349,8 @@ trait PathMatchers {
|
||||||
* unmatched part of the request's URI path as an (encoded!) String.
|
* unmatched part of the request's URI path as an (encoded!) String.
|
||||||
* If you need access to the remaining unencoded elements of the path
|
* If you need access to the remaining unencoded elements of the path
|
||||||
* use the `RestPath` matcher!
|
* use the `RestPath` matcher!
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object Rest extends PathMatcher1[String] {
|
object Rest extends PathMatcher1[String] {
|
||||||
def apply(path: Path) = Matched(Path.Empty, Tuple1(path.toString))
|
def apply(path: Path) = Matched(Path.Empty, Tuple1(path.toString))
|
||||||
|
|
@ -332,6 +359,8 @@ trait PathMatchers {
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that matches and extracts the complete remaining,
|
* A PathMatcher that matches and extracts the complete remaining,
|
||||||
* unmatched part of the request's URI path.
|
* unmatched part of the request's URI path.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object RestPath extends PathMatcher1[Path] {
|
object RestPath extends PathMatcher1[Path] {
|
||||||
def apply(path: Path) = Matched(Path.Empty, Tuple1(path))
|
def apply(path: Path) = Matched(Path.Empty, Tuple1(path))
|
||||||
|
|
@ -341,6 +370,8 @@ trait PathMatchers {
|
||||||
* A PathMatcher that efficiently matches a number of digits and extracts their (non-negative) Int value.
|
* A PathMatcher that efficiently matches a number of digits and extracts their (non-negative) Int value.
|
||||||
* The matcher will not match 0 digits or a sequence of digits that would represent an Int value larger
|
* The matcher will not match 0 digits or a sequence of digits that would represent an Int value larger
|
||||||
* than Int.MaxValue.
|
* than Int.MaxValue.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object IntNumber extends NumberMatcher[Int](Int.MaxValue, 10) {
|
object IntNumber extends NumberMatcher[Int](Int.MaxValue, 10) {
|
||||||
def fromChar(c: Char) = fromDecimalChar(c)
|
def fromChar(c: Char) = fromDecimalChar(c)
|
||||||
|
|
@ -350,6 +381,8 @@ trait PathMatchers {
|
||||||
* A PathMatcher that efficiently matches a number of digits and extracts their (non-negative) Long value.
|
* A PathMatcher that efficiently matches a number of digits and extracts their (non-negative) Long value.
|
||||||
* The matcher will not match 0 digits or a sequence of digits that would represent an Long value larger
|
* The matcher will not match 0 digits or a sequence of digits that would represent an Long value larger
|
||||||
* than Long.MaxValue.
|
* than Long.MaxValue.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object LongNumber extends NumberMatcher[Long](Long.MaxValue, 10) {
|
object LongNumber extends NumberMatcher[Long](Long.MaxValue, 10) {
|
||||||
def fromChar(c: Char) = fromDecimalChar(c)
|
def fromChar(c: Char) = fromDecimalChar(c)
|
||||||
|
|
@ -359,6 +392,8 @@ trait PathMatchers {
|
||||||
* A PathMatcher that efficiently matches a number of hex-digits and extracts their (non-negative) Int value.
|
* A PathMatcher that efficiently matches a number of hex-digits and extracts their (non-negative) Int value.
|
||||||
* The matcher will not match 0 digits or a sequence of digits that would represent an Int value larger
|
* The matcher will not match 0 digits or a sequence of digits that would represent an Int value larger
|
||||||
* than Int.MaxValue.
|
* than Int.MaxValue.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object HexIntNumber extends NumberMatcher[Int](Int.MaxValue, 16) {
|
object HexIntNumber extends NumberMatcher[Int](Int.MaxValue, 16) {
|
||||||
def fromChar(c: Char) = fromHexChar(c)
|
def fromChar(c: Char) = fromHexChar(c)
|
||||||
|
|
@ -368,12 +403,17 @@ trait PathMatchers {
|
||||||
* A PathMatcher that efficiently matches a number of hex-digits and extracts their (non-negative) Long value.
|
* A PathMatcher that efficiently matches a number of hex-digits and extracts their (non-negative) Long value.
|
||||||
* The matcher will not match 0 digits or a sequence of digits that would represent an Long value larger
|
* The matcher will not match 0 digits or a sequence of digits that would represent an Long value larger
|
||||||
* than Long.MaxValue.
|
* than Long.MaxValue.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object HexLongNumber extends NumberMatcher[Long](Long.MaxValue, 16) {
|
object HexLongNumber extends NumberMatcher[Long](Long.MaxValue, 16) {
|
||||||
def fromChar(c: Char) = fromHexChar(c)
|
def fromChar(c: Char) = fromHexChar(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// common implementation of Number matchers
|
// common implementation of Number matchers
|
||||||
|
/**
|
||||||
|
* @group pathmatcher
|
||||||
|
*/
|
||||||
abstract class NumberMatcher[@specialized(Int, Long) T](max: T, base: T)(implicit x: Integral[T])
|
abstract class NumberMatcher[@specialized(Int, Long) T](max: T, base: T)(implicit x: Integral[T])
|
||||||
extends PathMatcher1[T] {
|
extends PathMatcher1[T] {
|
||||||
|
|
||||||
|
|
@ -414,6 +454,8 @@ trait PathMatchers {
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that matches and extracts a Double value. The matched string representation is the pure decimal,
|
* A PathMatcher that matches and extracts a Double value. The matched string representation is the pure decimal,
|
||||||
* optionally signed form of a double value, i.e. without exponent.
|
* optionally signed form of a double value, i.e. without exponent.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
val DoubleNumber: PathMatcher1[Double] =
|
val DoubleNumber: PathMatcher1[Double] =
|
||||||
PathMatcher("""[+-]?\d*\.?\d*""".r) flatMap { string ⇒
|
PathMatcher("""[+-]?\d*\.?\d*""".r) flatMap { string ⇒
|
||||||
|
|
@ -423,6 +465,8 @@ trait PathMatchers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that matches and extracts a java.util.UUID instance.
|
* A PathMatcher that matches and extracts a java.util.UUID instance.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
val JavaUUID: PathMatcher1[UUID] =
|
val JavaUUID: PathMatcher1[UUID] =
|
||||||
PathMatcher("""[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}""".r) flatMap { string ⇒
|
PathMatcher("""[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}""".r) flatMap { string ⇒
|
||||||
|
|
@ -433,12 +477,16 @@ trait PathMatchers {
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that always matches, doesn't consume anything and extracts nothing.
|
* A PathMatcher that always matches, doesn't consume anything and extracts nothing.
|
||||||
* Serves mainly as a neutral element in PathMatcher composition.
|
* Serves mainly as a neutral element in PathMatcher composition.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
val Neutral: PathMatcher0 = PathMatcher.provide(())
|
val Neutral: PathMatcher0 = PathMatcher.provide(())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that matches if the unmatched path starts with a path segment.
|
* A PathMatcher that matches if the unmatched path starts with a path segment.
|
||||||
* If so the path segment is extracted as a String.
|
* If so the path segment is extracted as a String.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
object Segment extends PathMatcher1[String] {
|
object Segment extends PathMatcher1[String] {
|
||||||
def apply(path: Path) = path match {
|
def apply(path: Path) = path match {
|
||||||
|
|
@ -451,6 +499,8 @@ trait PathMatchers {
|
||||||
* A PathMatcher that matches up to 128 remaining segments as a List[String].
|
* A PathMatcher that matches up to 128 remaining segments as a List[String].
|
||||||
* This can also be no segments resulting in the empty list.
|
* This can also be no segments resulting in the empty list.
|
||||||
* If the path has a trailing slash this slash will *not* be matched.
|
* If the path has a trailing slash this slash will *not* be matched.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
val Segments: PathMatcher1[List[String]] = Segments(min = 0, max = 128)
|
val Segments: PathMatcher1[List[String]] = Segments(min = 0, max = 128)
|
||||||
|
|
||||||
|
|
@ -458,6 +508,8 @@ trait PathMatchers {
|
||||||
* A PathMatcher that matches the given number of path segments (separated by slashes) as a List[String].
|
* A PathMatcher that matches the given number of path segments (separated by slashes) as a List[String].
|
||||||
* If there are more than `count` segments present the remaining ones will be left unmatched.
|
* If there are more than `count` segments present the remaining ones will be left unmatched.
|
||||||
* If the path has a trailing slash this slash will *not* be matched.
|
* If the path has a trailing slash this slash will *not* be matched.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
def Segments(count: Int): PathMatcher1[List[String]] = Segment.repeat(count, separator = Slash)
|
def Segments(count: Int): PathMatcher1[List[String]] = Segment.repeat(count, separator = Slash)
|
||||||
|
|
||||||
|
|
@ -465,11 +517,15 @@ trait PathMatchers {
|
||||||
* A PathMatcher that matches between `min` and `max` (both inclusively) path segments (separated by slashes)
|
* A PathMatcher that matches between `min` and `max` (both inclusively) path segments (separated by slashes)
|
||||||
* as a List[String]. If there are more than `count` segments present the remaining ones will be left unmatched.
|
* as a List[String]. If there are more than `count` segments present the remaining ones will be left unmatched.
|
||||||
* If the path has a trailing slash this slash will *not* be matched.
|
* If the path has a trailing slash this slash will *not* be matched.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
def Segments(min: Int, max: Int): PathMatcher1[List[String]] = Segment.repeat(min, max, separator = Slash)
|
def Segments(min: Int, max: Int): PathMatcher1[List[String]] = Segment.repeat(min, max, separator = Slash)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A PathMatcher that never matches anything.
|
* A PathMatcher that never matches anything.
|
||||||
|
*
|
||||||
|
* @group pathmatcher
|
||||||
*/
|
*/
|
||||||
def nothingMatcher[L: Tuple]: PathMatcher[L] =
|
def nothingMatcher[L: Tuple]: PathMatcher[L] =
|
||||||
new PathMatcher[L] {
|
new PathMatcher[L] {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,15 @@ package akka.http.scaladsl.server
|
||||||
import akka.http.scaladsl.util.FastFuture
|
import akka.http.scaladsl.util.FastFuture
|
||||||
import akka.http.scaladsl.util.FastFuture._
|
import akka.http.scaladsl.util.FastFuture._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname concat Route concatenation
|
||||||
|
* @groupprio concat 300
|
||||||
|
*/
|
||||||
trait RouteConcatenation {
|
trait RouteConcatenation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group concat
|
||||||
|
*/
|
||||||
implicit def enhanceRouteWithConcatenation(route: Route): RouteConcatenation.RouteWithConcatenation =
|
implicit def enhanceRouteWithConcatenation(route: Route): RouteConcatenation.RouteWithConcatenation =
|
||||||
new RouteConcatenation.RouteWithConcatenation(route: Route)
|
new RouteConcatenation.RouteWithConcatenation(route: Route)
|
||||||
}
|
}
|
||||||
|
|
@ -32,4 +39,4 @@ object RouteConcatenation extends RouteConcatenation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,75 +15,131 @@ import akka.http.scaladsl.util.FastFuture
|
||||||
import akka.http.scaladsl.model._
|
import akka.http.scaladsl.model._
|
||||||
import akka.http.scaladsl.util.FastFuture._
|
import akka.http.scaladsl.util.FastFuture._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname basic Basic directives
|
||||||
|
* @groupprio basic 10
|
||||||
|
*/
|
||||||
trait BasicDirectives {
|
trait BasicDirectives {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapInnerRoute(f: Route ⇒ Route): Directive0 =
|
def mapInnerRoute(f: Route ⇒ Route): Directive0 =
|
||||||
Directive { inner ⇒ f(inner(())) }
|
Directive { inner ⇒ f(inner(())) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRequestContext(f: RequestContext ⇒ RequestContext): Directive0 =
|
def mapRequestContext(f: RequestContext ⇒ RequestContext): Directive0 =
|
||||||
mapInnerRoute { inner ⇒ ctx ⇒ inner(f(ctx)) }
|
mapInnerRoute { inner ⇒ ctx ⇒ inner(f(ctx)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRequest(f: HttpRequest ⇒ HttpRequest): Directive0 =
|
def mapRequest(f: HttpRequest ⇒ HttpRequest): Directive0 =
|
||||||
mapRequestContext(_ mapRequest f)
|
mapRequestContext(_ mapRequest f)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRouteResultFuture(f: Future[RouteResult] ⇒ Future[RouteResult]): Directive0 =
|
def mapRouteResultFuture(f: Future[RouteResult] ⇒ Future[RouteResult]): Directive0 =
|
||||||
Directive { inner ⇒ ctx ⇒ f(inner(())(ctx)) }
|
Directive { inner ⇒ ctx ⇒ f(inner(())(ctx)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRouteResult(f: RouteResult ⇒ RouteResult): Directive0 =
|
def mapRouteResult(f: RouteResult ⇒ RouteResult): Directive0 =
|
||||||
Directive { inner ⇒ ctx ⇒ inner(())(ctx).fast.map(f)(ctx.executionContext) }
|
Directive { inner ⇒ ctx ⇒ inner(())(ctx).fast.map(f)(ctx.executionContext) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRouteResultWith(f: RouteResult ⇒ Future[RouteResult]): Directive0 =
|
def mapRouteResultWith(f: RouteResult ⇒ Future[RouteResult]): Directive0 =
|
||||||
Directive { inner ⇒ ctx ⇒ inner(())(ctx).fast.flatMap(f)(ctx.executionContext) }
|
Directive { inner ⇒ ctx ⇒ inner(())(ctx).fast.flatMap(f)(ctx.executionContext) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRouteResultPF(f: PartialFunction[RouteResult, RouteResult]): Directive0 =
|
def mapRouteResultPF(f: PartialFunction[RouteResult, RouteResult]): Directive0 =
|
||||||
mapRouteResult(f.applyOrElse(_, conforms[RouteResult]))
|
mapRouteResult(f.applyOrElse(_, conforms[RouteResult]))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRouteResultWithPF(f: PartialFunction[RouteResult, Future[RouteResult]]): Directive0 =
|
def mapRouteResultWithPF(f: PartialFunction[RouteResult, Future[RouteResult]]): Directive0 =
|
||||||
mapRouteResultWith(f.applyOrElse(_, FastFuture.successful[RouteResult]))
|
mapRouteResultWith(f.applyOrElse(_, FastFuture.successful[RouteResult]))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def recoverRejections(f: immutable.Seq[Rejection] ⇒ RouteResult): Directive0 =
|
def recoverRejections(f: immutable.Seq[Rejection] ⇒ RouteResult): Directive0 =
|
||||||
mapRouteResultPF { case RouteResult.Rejected(rejections) ⇒ f(rejections) }
|
mapRouteResultPF { case RouteResult.Rejected(rejections) ⇒ f(rejections) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def recoverRejectionsWith(f: immutable.Seq[Rejection] ⇒ Future[RouteResult]): Directive0 =
|
def recoverRejectionsWith(f: immutable.Seq[Rejection] ⇒ Future[RouteResult]): Directive0 =
|
||||||
mapRouteResultWithPF { case RouteResult.Rejected(rejections) ⇒ f(rejections) }
|
mapRouteResultWithPF { case RouteResult.Rejected(rejections) ⇒ f(rejections) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapRejections(f: immutable.Seq[Rejection] ⇒ immutable.Seq[Rejection]): Directive0 =
|
def mapRejections(f: immutable.Seq[Rejection] ⇒ immutable.Seq[Rejection]): Directive0 =
|
||||||
recoverRejections(rejections ⇒ RouteResult.Rejected(f(rejections)))
|
recoverRejections(rejections ⇒ RouteResult.Rejected(f(rejections)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapResponse(f: HttpResponse ⇒ HttpResponse): Directive0 =
|
def mapResponse(f: HttpResponse ⇒ HttpResponse): Directive0 =
|
||||||
mapRouteResultPF { case RouteResult.Complete(response) ⇒ RouteResult.Complete(f(response)) }
|
mapRouteResultPF { case RouteResult.Complete(response) ⇒ RouteResult.Complete(f(response)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapResponseEntity(f: ResponseEntity ⇒ ResponseEntity): Directive0 =
|
def mapResponseEntity(f: ResponseEntity ⇒ ResponseEntity): Directive0 =
|
||||||
mapResponse(_ mapEntity f)
|
mapResponse(_ mapEntity f)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group basic
|
||||||
|
*/
|
||||||
def mapResponseHeaders(f: immutable.Seq[HttpHeader] ⇒ immutable.Seq[HttpHeader]): Directive0 =
|
def mapResponseHeaders(f: immutable.Seq[HttpHeader] ⇒ immutable.Seq[HttpHeader]): Directive0 =
|
||||||
mapResponse(_ mapHeaders f)
|
mapResponse(_ mapHeaders f)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Directive0 that always passes the request on to its inner route
|
* A Directive0 that always passes the request on to its inner route
|
||||||
* (i.e. does nothing with the request or the response).
|
* (i.e. does nothing with the request or the response).
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def pass: Directive0 = Directive.Empty
|
def pass: Directive0 = Directive.Empty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injects the given value into a directive.
|
* Injects the given value into a directive.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def provide[T](value: T): Directive1[T] = tprovide(Tuple1(value))
|
def provide[T](value: T): Directive1[T] = tprovide(Tuple1(value))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injects the given values into a directive.
|
* Injects the given values into a directive.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def tprovide[L: Tuple](values: L): Directive[L] =
|
def tprovide[L: Tuple](values: L): Directive[L] =
|
||||||
Directive { _(values) }
|
Directive { _(values) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a single value using the given function.
|
* Extracts a single value using the given function.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extract[T](f: RequestContext ⇒ T): Directive1[T] =
|
def extract[T](f: RequestContext ⇒ T): Directive1[T] =
|
||||||
textract(ctx ⇒ Tuple1(f(ctx)))
|
textract(ctx ⇒ Tuple1(f(ctx)))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a number of values using the given function.
|
* Extracts a number of values using the given function.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def textract[L: Tuple](f: RequestContext ⇒ L): Directive[L] =
|
def textract[L: Tuple](f: RequestContext ⇒ L): Directive[L] =
|
||||||
Directive { inner ⇒ ctx ⇒ inner(f(ctx))(ctx) }
|
Directive { inner ⇒ ctx ⇒ inner(f(ctx))(ctx) }
|
||||||
|
|
@ -91,6 +147,8 @@ trait BasicDirectives {
|
||||||
/**
|
/**
|
||||||
* Adds a TransformationRejection cancelling all rejections equal to the given one
|
* Adds a TransformationRejection cancelling all rejections equal to the given one
|
||||||
* to the list of rejections potentially coming back from the inner route.
|
* to the list of rejections potentially coming back from the inner route.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def cancelRejection(rejection: Rejection): Directive0 =
|
def cancelRejection(rejection: Rejection): Directive0 =
|
||||||
cancelRejections(_ == rejection)
|
cancelRejections(_ == rejection)
|
||||||
|
|
@ -98,6 +156,8 @@ trait BasicDirectives {
|
||||||
/**
|
/**
|
||||||
* Adds a TransformationRejection cancelling all rejections of one of the given classes
|
* Adds a TransformationRejection cancelling all rejections of one of the given classes
|
||||||
* to the list of rejections potentially coming back from the inner route.
|
* to the list of rejections potentially coming back from the inner route.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def cancelRejections(classes: Class[_]*): Directive0 =
|
def cancelRejections(classes: Class[_]*): Directive0 =
|
||||||
cancelRejections(r ⇒ classes.exists(_ isInstance r))
|
cancelRejections(r ⇒ classes.exists(_ isInstance r))
|
||||||
|
|
@ -105,91 +165,123 @@ trait BasicDirectives {
|
||||||
/**
|
/**
|
||||||
* Adds a TransformationRejection cancelling all rejections for which the given filter function returns true
|
* Adds a TransformationRejection cancelling all rejections for which the given filter function returns true
|
||||||
* to the list of rejections potentially coming back from the inner route.
|
* to the list of rejections potentially coming back from the inner route.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def cancelRejections(cancelFilter: Rejection ⇒ Boolean): Directive0 =
|
def cancelRejections(cancelFilter: Rejection ⇒ Boolean): Directive0 =
|
||||||
mapRejections(_ :+ TransformationRejection(_ filterNot cancelFilter))
|
mapRejections(_ :+ TransformationRejection(_ filterNot cancelFilter))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms the unmatchedPath of the RequestContext using the given function.
|
* Transforms the unmatchedPath of the RequestContext using the given function.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def mapUnmatchedPath(f: Uri.Path ⇒ Uri.Path): Directive0 =
|
def mapUnmatchedPath(f: Uri.Path ⇒ Uri.Path): Directive0 =
|
||||||
mapRequestContext(_ mapUnmatchedPath f)
|
mapRequestContext(_ mapUnmatchedPath f)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the yet unmatched path from the RequestContext.
|
* Extracts the yet unmatched path from the RequestContext.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractUnmatchedPath: Directive1[Uri.Path] = BasicDirectives._extractUnmatchedPath
|
def extractUnmatchedPath: Directive1[Uri.Path] = BasicDirectives._extractUnmatchedPath
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the current [[HttpRequest]] instance.
|
* Extracts the current [[HttpRequest]] instance.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractRequest: Directive1[HttpRequest] = BasicDirectives._extractRequest
|
def extractRequest: Directive1[HttpRequest] = BasicDirectives._extractRequest
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the complete request URI.
|
* Extracts the complete request URI.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractUri: Directive1[Uri] = BasicDirectives._extractUri
|
def extractUri: Directive1[Uri] = BasicDirectives._extractUri
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs its inner route with the given alternative [[scala.concurrent.ExecutionContextExecutor]].
|
* Runs its inner route with the given alternative [[scala.concurrent.ExecutionContextExecutor]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def withExecutionContext(ec: ExecutionContextExecutor): Directive0 =
|
def withExecutionContext(ec: ExecutionContextExecutor): Directive0 =
|
||||||
mapRequestContext(_ withExecutionContext ec)
|
mapRequestContext(_ withExecutionContext ec)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the [[scala.concurrent.ExecutionContextExecutor]] from the [[akka.http.scaladsl.server.RequestContext]].
|
* Extracts the [[scala.concurrent.ExecutionContextExecutor]] from the [[akka.http.scaladsl.server.RequestContext]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractExecutionContext: Directive1[ExecutionContextExecutor] = BasicDirectives._extractExecutionContext
|
def extractExecutionContext: Directive1[ExecutionContextExecutor] = BasicDirectives._extractExecutionContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs its inner route with the given alternative [[akka.stream.Materializer]].
|
* Runs its inner route with the given alternative [[akka.stream.Materializer]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def withMaterializer(materializer: Materializer): Directive0 =
|
def withMaterializer(materializer: Materializer): Directive0 =
|
||||||
mapRequestContext(_ withMaterializer materializer)
|
mapRequestContext(_ withMaterializer materializer)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the [[akka.stream.Materializer]] from the [[akka.http.scaladsl.server.RequestContext]].
|
* Extracts the [[akka.stream.Materializer]] from the [[akka.http.scaladsl.server.RequestContext]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractMaterializer: Directive1[Materializer] = BasicDirectives._extractMaterializer
|
def extractMaterializer: Directive1[Materializer] = BasicDirectives._extractMaterializer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs its inner route with the given alternative [[akka.event.LoggingAdapter]].
|
* Runs its inner route with the given alternative [[akka.event.LoggingAdapter]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def withLog(log: LoggingAdapter): Directive0 =
|
def withLog(log: LoggingAdapter): Directive0 =
|
||||||
mapRequestContext(_ withLog log)
|
mapRequestContext(_ withLog log)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the [[akka.event.LoggingAdapter]] from the [[akka.http.scaladsl.server.RequestContext]].
|
* Extracts the [[akka.event.LoggingAdapter]] from the [[akka.http.scaladsl.server.RequestContext]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractLog: Directive1[LoggingAdapter] =
|
def extractLog: Directive1[LoggingAdapter] =
|
||||||
BasicDirectives._extractLog
|
BasicDirectives._extractLog
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs its inner route with the given alternative [[RoutingSettings]].
|
* Runs its inner route with the given alternative [[RoutingSettings]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def withSettings(settings: RoutingSettings): Directive0 =
|
def withSettings(settings: RoutingSettings): Directive0 =
|
||||||
mapRequestContext(_ withRoutingSettings settings)
|
mapRequestContext(_ withRoutingSettings settings)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the inner route with settings mapped by the given function.
|
* Runs the inner route with settings mapped by the given function.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def mapSettings(f: RoutingSettings ⇒ RoutingSettings): Directive0 =
|
def mapSettings(f: RoutingSettings ⇒ RoutingSettings): Directive0 =
|
||||||
mapRequestContext(ctx ⇒ ctx.withRoutingSettings(f(ctx.settings)))
|
mapRequestContext(ctx ⇒ ctx.withRoutingSettings(f(ctx.settings)))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the [[RoutingSettings]] from the [[akka.http.scaladsl.server.RequestContext]].
|
* Extracts the [[RoutingSettings]] from the [[akka.http.scaladsl.server.RequestContext]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractSettings: Directive1[RoutingSettings] =
|
def extractSettings: Directive1[RoutingSettings] =
|
||||||
BasicDirectives._extractSettings
|
BasicDirectives._extractSettings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the [[akka.http.scaladsl.settings.ParserSettings]] from the [[akka.http.scaladsl.server.RequestContext]].
|
* Extracts the [[akka.http.scaladsl.settings.ParserSettings]] from the [[akka.http.scaladsl.server.RequestContext]].
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractParserSettings: Directive1[ParserSettings] =
|
def extractParserSettings: Directive1[ParserSettings] =
|
||||||
BasicDirectives._extractParserSettings
|
BasicDirectives._extractParserSettings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the [[akka.http.scaladsl.server.RequestContext]] itself.
|
* Extracts the [[akka.http.scaladsl.server.RequestContext]] itself.
|
||||||
|
*
|
||||||
|
* @group basic
|
||||||
*/
|
*/
|
||||||
def extractRequestContext: Directive1[RequestContext] = BasicDirectives._extractRequestContext
|
def extractRequestContext: Directive1[RequestContext] = BasicDirectives._extractRequestContext
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ import HttpMethods._
|
||||||
import StatusCodes._
|
import StatusCodes._
|
||||||
import EntityTag._
|
import EntityTag._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname cachecondition Cache condition directives
|
||||||
|
* @groupprio cachecondition 20
|
||||||
|
*/
|
||||||
trait CacheConditionDirectives {
|
trait CacheConditionDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
import RouteDirectives._
|
import RouteDirectives._
|
||||||
|
|
@ -26,6 +30,8 @@ trait CacheConditionDirectives {
|
||||||
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
||||||
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
||||||
* must be on a deeper level in your route structure in order to function correctly.
|
* must be on a deeper level in your route structure in order to function correctly.
|
||||||
|
*
|
||||||
|
* @group cachecondition
|
||||||
*/
|
*/
|
||||||
def conditional(eTag: EntityTag): Directive0 = conditional(Some(eTag), None)
|
def conditional(eTag: EntityTag): Directive0 = conditional(Some(eTag), None)
|
||||||
|
|
||||||
|
|
@ -39,6 +45,8 @@ trait CacheConditionDirectives {
|
||||||
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
||||||
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
||||||
* must be on a deeper level in your route structure in order to function correctly.
|
* must be on a deeper level in your route structure in order to function correctly.
|
||||||
|
*
|
||||||
|
* @group cachecondition
|
||||||
*/
|
*/
|
||||||
def conditional(lastModified: DateTime): Directive0 = conditional(None, Some(lastModified))
|
def conditional(lastModified: DateTime): Directive0 = conditional(None, Some(lastModified))
|
||||||
|
|
||||||
|
|
@ -52,6 +60,8 @@ trait CacheConditionDirectives {
|
||||||
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
||||||
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
||||||
* must be on a deeper level in your route structure in order to function correctly.
|
* must be on a deeper level in your route structure in order to function correctly.
|
||||||
|
*
|
||||||
|
* @group cachecondition
|
||||||
*/
|
*/
|
||||||
def conditional(eTag: EntityTag, lastModified: DateTime): Directive0 = conditional(Some(eTag), Some(lastModified))
|
def conditional(eTag: EntityTag, lastModified: DateTime): Directive0 = conditional(Some(eTag), Some(lastModified))
|
||||||
|
|
||||||
|
|
@ -65,6 +75,8 @@ trait CacheConditionDirectives {
|
||||||
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
* Note: if you want to combine this directive with `withRangeSupport(...)` you need to put
|
||||||
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
* it on the *outside* of the `withRangeSupport(...)` directive, i.e. `withRangeSupport(...)`
|
||||||
* must be on a deeper level in your route structure in order to function correctly.
|
* must be on a deeper level in your route structure in order to function correctly.
|
||||||
|
*
|
||||||
|
* @group cachecondition
|
||||||
*/
|
*/
|
||||||
def conditional(eTag: Option[EntityTag], lastModified: Option[DateTime]): Directive0 = {
|
def conditional(eTag: Option[EntityTag], lastModified: Option[DateTime]): Directive0 = {
|
||||||
def addResponseHeaders: Directive0 =
|
def addResponseHeaders: Directive0 =
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ import akka.http.scaladsl.model._
|
||||||
import akka.http.scaladsl.coding._
|
import akka.http.scaladsl.coding._
|
||||||
import akka.http.impl.util._
|
import akka.http.impl.util._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname coding Coding directives
|
||||||
|
* @groupprio coding 50
|
||||||
|
*/
|
||||||
trait CodingDirectives {
|
trait CodingDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
import MiscDirectives._
|
import MiscDirectives._
|
||||||
|
|
@ -23,6 +27,8 @@ trait CodingDirectives {
|
||||||
/**
|
/**
|
||||||
* Rejects the request with an UnacceptedResponseEncodingRejection
|
* Rejects the request with an UnacceptedResponseEncodingRejection
|
||||||
* if the given response encoding is not accepted by the client.
|
* if the given response encoding is not accepted by the client.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def responseEncodingAccepted(encoding: HttpEncoding): Directive0 =
|
def responseEncodingAccepted(encoding: HttpEncoding): Directive0 =
|
||||||
extractRequest.flatMap { request ⇒
|
extractRequest.flatMap { request ⇒
|
||||||
|
|
@ -37,6 +43,8 @@ trait CodingDirectives {
|
||||||
*
|
*
|
||||||
* If the `Accept-Encoding` header is missing or empty or specifies an encoding other than
|
* If the `Accept-Encoding` header is missing or empty or specifies an encoding other than
|
||||||
* identity, gzip or deflate then no encoding is used.
|
* identity, gzip or deflate then no encoding is used.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def encodeResponse: Directive0 =
|
def encodeResponse: Directive0 =
|
||||||
_encodeResponse(DefaultEncodeResponseEncoders)
|
_encodeResponse(DefaultEncodeResponseEncoders)
|
||||||
|
|
@ -51,6 +59,8 @@ trait CodingDirectives {
|
||||||
*
|
*
|
||||||
* If the `Accept-Encoding` header is empty and `NoCoding` is part of the encoders then no
|
* If the `Accept-Encoding` header is empty and `NoCoding` is part of the encoders then no
|
||||||
* response encoding is used. Otherwise the request is rejected.
|
* response encoding is used. Otherwise the request is rejected.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def encodeResponseWith(first: Encoder, more: Encoder*): Directive0 =
|
def encodeResponseWith(first: Encoder, more: Encoder*): Directive0 =
|
||||||
_encodeResponse(immutable.Seq(first +: more: _*))
|
_encodeResponse(immutable.Seq(first +: more: _*))
|
||||||
|
|
@ -60,6 +70,8 @@ trait CodingDirectives {
|
||||||
/**
|
/**
|
||||||
* Decodes the incoming request using the given Decoder.
|
* Decodes the incoming request using the given Decoder.
|
||||||
* If the request encoding doesn't match the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
* If the request encoding doesn't match the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def decodeRequestWith(decoder: Decoder): Directive0 = {
|
def decodeRequestWith(decoder: Decoder): Directive0 = {
|
||||||
def applyDecoder =
|
def applyDecoder =
|
||||||
|
|
@ -85,6 +97,8 @@ trait CodingDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects the request with an UnsupportedRequestEncodingRejection if its encoding doesn't match the given one.
|
* Rejects the request with an UnsupportedRequestEncodingRejection if its encoding doesn't match the given one.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def requestEncodedWith(encoding: HttpEncoding): Directive0 =
|
def requestEncodedWith(encoding: HttpEncoding): Directive0 =
|
||||||
extract(_.request.encoding).flatMap {
|
extract(_.request.encoding).flatMap {
|
||||||
|
|
@ -97,6 +111,8 @@ trait CodingDirectives {
|
||||||
* encoders. If the request encoding doesn't match one of the given encoders
|
* encoders. If the request encoding doesn't match one of the given encoders
|
||||||
* the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
* the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
||||||
* If no decoders are given the default encoders (`Gzip`, `Deflate`, `NoCoding`) are used.
|
* If no decoders are given the default encoders (`Gzip`, `Deflate`, `NoCoding`) are used.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def decodeRequestWith(decoders: Decoder*): Directive0 =
|
def decodeRequestWith(decoders: Decoder*): Directive0 =
|
||||||
theseOrDefault(decoders).map(decodeRequestWith).reduce(_ | _)
|
theseOrDefault(decoders).map(decodeRequestWith).reduce(_ | _)
|
||||||
|
|
@ -105,6 +121,8 @@ trait CodingDirectives {
|
||||||
* Decompresses the incoming request if it is `gzip` or `deflate` compressed.
|
* Decompresses the incoming request if it is `gzip` or `deflate` compressed.
|
||||||
* Uncompressed requests are passed through untouched.
|
* Uncompressed requests are passed through untouched.
|
||||||
* If the request encoded with another encoding the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
* If the request encoded with another encoding the request is rejected with an `UnsupportedRequestEncodingRejection`.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def decodeRequest: Directive0 =
|
def decodeRequest: Directive0 =
|
||||||
decodeRequestWith(DefaultCoders: _*)
|
decodeRequestWith(DefaultCoders: _*)
|
||||||
|
|
@ -112,6 +130,8 @@ trait CodingDirectives {
|
||||||
/**
|
/**
|
||||||
* Inspects the response entity and adds a `Content-Encoding: gzip` response header if
|
* Inspects the response entity and adds a `Content-Encoding: gzip` response header if
|
||||||
* the entities media-type is precompressed with gzip and no `Content-Encoding` header is present yet.
|
* the entities media-type is precompressed with gzip and no `Content-Encoding` header is present yet.
|
||||||
|
*
|
||||||
|
* @group coding
|
||||||
*/
|
*/
|
||||||
def withPrecompressedMediaTypeSupport: Directive0 =
|
def withPrecompressedMediaTypeSupport: Directive0 =
|
||||||
mapResponse { response ⇒
|
mapResponse { response ⇒
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ import akka.http.scaladsl.model._
|
||||||
import akka.http.scaladsl.model.headers._
|
import akka.http.scaladsl.model.headers._
|
||||||
import akka.http.impl.util._
|
import akka.http.impl.util._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname cookie Cookie directives
|
||||||
|
* @groupprio cookie 30
|
||||||
|
*/
|
||||||
trait CookieDirectives {
|
trait CookieDirectives {
|
||||||
import HeaderDirectives._
|
import HeaderDirectives._
|
||||||
import RespondWithDirectives._
|
import RespondWithDirectives._
|
||||||
|
|
@ -17,6 +21,8 @@ trait CookieDirectives {
|
||||||
/**
|
/**
|
||||||
* Extracts the [[HttpCookiePair]] with the given name. If the cookie is not present the
|
* Extracts the [[HttpCookiePair]] with the given name. If the cookie is not present the
|
||||||
* request is rejected with a respective [[MissingCookieRejection]].
|
* request is rejected with a respective [[MissingCookieRejection]].
|
||||||
|
*
|
||||||
|
* @group cookie
|
||||||
*/
|
*/
|
||||||
def cookie(name: String): Directive1[HttpCookiePair] =
|
def cookie(name: String): Directive1[HttpCookiePair] =
|
||||||
headerValue(findCookie(name)) | reject(MissingCookieRejection(name))
|
headerValue(findCookie(name)) | reject(MissingCookieRejection(name))
|
||||||
|
|
@ -24,6 +30,8 @@ trait CookieDirectives {
|
||||||
/**
|
/**
|
||||||
* Extracts the [[HttpCookiePair]] with the given name as an `Option[HttpCookiePair]`.
|
* Extracts the [[HttpCookiePair]] with the given name as an `Option[HttpCookiePair]`.
|
||||||
* If the cookie is not present a value of `None` is extracted.
|
* If the cookie is not present a value of `None` is extracted.
|
||||||
|
*
|
||||||
|
* @group cookie
|
||||||
*/
|
*/
|
||||||
def optionalCookie(name: String): Directive1[Option[HttpCookiePair]] =
|
def optionalCookie(name: String): Directive1[Option[HttpCookiePair]] =
|
||||||
optionalHeaderValue(findCookie(name))
|
optionalHeaderValue(findCookie(name))
|
||||||
|
|
@ -35,12 +43,16 @@ trait CookieDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a [[Set-Cookie]] response header with the given cookies.
|
* Adds a [[Set-Cookie]] response header with the given cookies.
|
||||||
|
*
|
||||||
|
* @group cookie
|
||||||
*/
|
*/
|
||||||
def setCookie(first: HttpCookie, more: HttpCookie*): Directive0 =
|
def setCookie(first: HttpCookie, more: HttpCookie*): Directive0 =
|
||||||
respondWithHeaders((first :: more.toList).map(`Set-Cookie`(_)))
|
respondWithHeaders((first :: more.toList).map(`Set-Cookie`(_)))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a [[Set-Cookie]] response header expiring the given cookies.
|
* Adds a [[Set-Cookie]] response header expiring the given cookies.
|
||||||
|
*
|
||||||
|
* @group cookie
|
||||||
*/
|
*/
|
||||||
def deleteCookie(first: HttpCookie, more: HttpCookie*): Directive0 =
|
def deleteCookie(first: HttpCookie, more: HttpCookie*): Directive0 =
|
||||||
respondWithHeaders((first :: more.toList).map { c ⇒
|
respondWithHeaders((first :: more.toList).map { c ⇒
|
||||||
|
|
@ -49,6 +61,8 @@ trait CookieDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a [[Set-Cookie]] response header expiring the cookie with the given properties.
|
* Adds a [[Set-Cookie]] response header expiring the cookie with the given properties.
|
||||||
|
*
|
||||||
|
* @group cookie
|
||||||
*/
|
*/
|
||||||
def deleteCookie(name: String, domain: String = "", path: String = ""): Directive0 =
|
def deleteCookie(name: String, domain: String = "", path: String = ""): Directive0 =
|
||||||
deleteCookie(HttpCookie(name, "", domain = domain.toOption, path = path.toOption))
|
deleteCookie(HttpCookie(name, "", domain = domain.toOption, path = path.toOption))
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,17 @@ import akka.event.Logging._
|
||||||
import akka.event.LoggingAdapter
|
import akka.event.LoggingAdapter
|
||||||
import akka.http.scaladsl.model._
|
import akka.http.scaladsl.model._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname debugging Debugging directives
|
||||||
|
* @groupprio debugging 40
|
||||||
|
*/
|
||||||
trait DebuggingDirectives {
|
trait DebuggingDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces a log entry for every incoming request.
|
* Produces a log entry for every incoming request.
|
||||||
|
*
|
||||||
|
* @group debugging
|
||||||
*/
|
*/
|
||||||
def logRequest(magnet: LoggingMagnet[HttpRequest ⇒ Unit]): Directive0 =
|
def logRequest(magnet: LoggingMagnet[HttpRequest ⇒ Unit]): Directive0 =
|
||||||
extractRequestContext.flatMap { ctx ⇒
|
extractRequestContext.flatMap { ctx ⇒
|
||||||
|
|
@ -23,6 +29,8 @@ trait DebuggingDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces a log entry for every [[RouteResult]].
|
* Produces a log entry for every [[RouteResult]].
|
||||||
|
*
|
||||||
|
* @group debugging
|
||||||
*/
|
*/
|
||||||
def logResult(magnet: LoggingMagnet[RouteResult ⇒ Unit]): Directive0 =
|
def logResult(magnet: LoggingMagnet[RouteResult ⇒ Unit]): Directive0 =
|
||||||
extractRequestContext.flatMap { ctx ⇒
|
extractRequestContext.flatMap { ctx ⇒
|
||||||
|
|
@ -34,6 +42,8 @@ trait DebuggingDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces a log entry for every incoming request and [[RouteResult]].
|
* Produces a log entry for every incoming request and [[RouteResult]].
|
||||||
|
*
|
||||||
|
* @group debugging
|
||||||
*/
|
*/
|
||||||
def logRequestResult(magnet: LoggingMagnet[HttpRequest ⇒ RouteResult ⇒ Unit]): Directive0 =
|
def logRequestResult(magnet: LoggingMagnet[HttpRequest ⇒ RouteResult ⇒ Unit]): Directive0 =
|
||||||
extractRequestContext.flatMap { ctx ⇒
|
extractRequestContext.flatMap { ctx ⇒
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,18 @@ import scala.util.control.NonFatal
|
||||||
import akka.http.scaladsl.util.FastFuture
|
import akka.http.scaladsl.util.FastFuture
|
||||||
import akka.http.scaladsl.util.FastFuture._
|
import akka.http.scaladsl.util.FastFuture._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname execution Execution directives
|
||||||
|
* @groupprio execution 60
|
||||||
|
*/
|
||||||
trait ExecutionDirectives {
|
trait ExecutionDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms exceptions thrown during evaluation of its inner route using the given
|
* Transforms exceptions thrown during evaluation of its inner route using the given
|
||||||
* [[akka.http.scaladsl.server.ExceptionHandler]].
|
* [[akka.http.scaladsl.server.ExceptionHandler]].
|
||||||
|
*
|
||||||
|
* @group execution
|
||||||
*/
|
*/
|
||||||
def handleExceptions(handler: ExceptionHandler): Directive0 =
|
def handleExceptions(handler: ExceptionHandler): Directive0 =
|
||||||
Directive { innerRouteBuilder ⇒
|
Directive { innerRouteBuilder ⇒
|
||||||
|
|
@ -33,6 +39,8 @@ trait ExecutionDirectives {
|
||||||
/**
|
/**
|
||||||
* Transforms rejections produced by its inner route using the given
|
* Transforms rejections produced by its inner route using the given
|
||||||
* [[akka.http.scaladsl.server.RejectionHandler]].
|
* [[akka.http.scaladsl.server.RejectionHandler]].
|
||||||
|
*
|
||||||
|
* @group execution
|
||||||
*/
|
*/
|
||||||
def handleRejections(handler: RejectionHandler): Directive0 =
|
def handleRejections(handler: RejectionHandler): Directive0 =
|
||||||
extractRequestContext flatMap { ctx ⇒
|
extractRequestContext flatMap { ctx ⇒
|
||||||
|
|
@ -55,4 +63,4 @@ trait ExecutionDirectives {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ExecutionDirectives extends ExecutionDirectives
|
object ExecutionDirectives extends ExecutionDirectives
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ import akka.http.scaladsl.model._
|
||||||
import akka.http.scaladsl.model.headers._
|
import akka.http.scaladsl.model.headers._
|
||||||
import akka.http.impl.util._
|
import akka.http.impl.util._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname fileandresource File and resource directives
|
||||||
|
* @groupprio fileandresource 70
|
||||||
|
*/
|
||||||
trait FileAndResourceDirectives {
|
trait FileAndResourceDirectives {
|
||||||
import CacheConditionDirectives._
|
import CacheConditionDirectives._
|
||||||
import MethodDirectives._
|
import MethodDirectives._
|
||||||
|
|
@ -30,6 +34,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Completes GET requests with the content of the given file.
|
* Completes GET requests with the content of the given file.
|
||||||
* If the file cannot be found or read the request is rejected.
|
* If the file cannot be found or read the request is rejected.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromFile(fileName: String)(implicit resolver: ContentTypeResolver): Route =
|
def getFromFile(fileName: String)(implicit resolver: ContentTypeResolver): Route =
|
||||||
getFromFile(new File(fileName))
|
getFromFile(new File(fileName))
|
||||||
|
|
@ -37,6 +43,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Completes GET requests with the content of the given file.
|
* Completes GET requests with the content of the given file.
|
||||||
* If the file cannot be found or read the request is rejected.
|
* If the file cannot be found or read the request is rejected.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromFile(file: File)(implicit resolver: ContentTypeResolver): Route =
|
def getFromFile(file: File)(implicit resolver: ContentTypeResolver): Route =
|
||||||
getFromFile(file, resolver(file.getName))
|
getFromFile(file, resolver(file.getName))
|
||||||
|
|
@ -44,6 +52,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Completes GET requests with the content of the given file.
|
* Completes GET requests with the content of the given file.
|
||||||
* If the file cannot be found or read the request is rejected.
|
* If the file cannot be found or read the request is rejected.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromFile(file: File, contentType: ContentType): Route =
|
def getFromFile(file: File, contentType: ContentType): Route =
|
||||||
get {
|
get {
|
||||||
|
|
@ -72,6 +82,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Completes GET requests with the content of the given class-path resource.
|
* Completes GET requests with the content of the given class-path resource.
|
||||||
* If the resource cannot be found or read the Route rejects the request.
|
* If the resource cannot be found or read the Route rejects the request.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromResource(resourceName: String)(implicit resolver: ContentTypeResolver): Route =
|
def getFromResource(resourceName: String)(implicit resolver: ContentTypeResolver): Route =
|
||||||
getFromResource(resourceName, resolver(resourceName))
|
getFromResource(resourceName, resolver(resourceName))
|
||||||
|
|
@ -79,6 +91,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Completes GET requests with the content of the given resource.
|
* Completes GET requests with the content of the given resource.
|
||||||
* If the resource is a directory or cannot be found or read the Route rejects the request.
|
* If the resource is a directory or cannot be found or read the Route rejects the request.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromResource(resourceName: String, contentType: ContentType, classLoader: ClassLoader = defaultClassLoader): Route =
|
def getFromResource(resourceName: String, contentType: ContentType, classLoader: ClassLoader = defaultClassLoader): Route =
|
||||||
if (!resourceName.endsWith("/"))
|
if (!resourceName.endsWith("/"))
|
||||||
|
|
@ -104,6 +118,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Completes GET requests with the content of a file underneath the given directory.
|
* Completes GET requests with the content of a file underneath the given directory.
|
||||||
* If the file cannot be read the Route rejects the request.
|
* If the file cannot be read the Route rejects the request.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromDirectory(directoryName: String)(implicit resolver: ContentTypeResolver): Route = {
|
def getFromDirectory(directoryName: String)(implicit resolver: ContentTypeResolver): Route = {
|
||||||
val base = withTrailingSlash(directoryName)
|
val base = withTrailingSlash(directoryName)
|
||||||
|
|
@ -120,6 +136,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Completes GET requests with a unified listing of the contents of all given directories.
|
* Completes GET requests with a unified listing of the contents of all given directories.
|
||||||
* The actual rendering of the directory contents is performed by the in-scope `Marshaller[DirectoryListing]`.
|
* The actual rendering of the directory contents is performed by the in-scope `Marshaller[DirectoryListing]`.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def listDirectoryContents(directories: String*)(implicit renderer: DirectoryRenderer): Route =
|
def listDirectoryContents(directories: String*)(implicit renderer: DirectoryRenderer): Route =
|
||||||
get {
|
get {
|
||||||
|
|
@ -147,6 +165,8 @@ trait FileAndResourceDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as `getFromBrowseableDirectories` with only one directory.
|
* Same as `getFromBrowseableDirectories` with only one directory.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromBrowseableDirectory(directory: String)(implicit renderer: DirectoryRenderer, resolver: ContentTypeResolver): Route =
|
def getFromBrowseableDirectory(directory: String)(implicit renderer: DirectoryRenderer, resolver: ContentTypeResolver): Route =
|
||||||
getFromBrowseableDirectories(directory)
|
getFromBrowseableDirectories(directory)
|
||||||
|
|
@ -154,6 +174,8 @@ trait FileAndResourceDirectives {
|
||||||
/**
|
/**
|
||||||
* Serves the content of the given directories as a file system browser, i.e. files are sent and directories
|
* Serves the content of the given directories as a file system browser, i.e. files are sent and directories
|
||||||
* served as browseable listings.
|
* served as browseable listings.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromBrowseableDirectories(directories: String*)(implicit renderer: DirectoryRenderer, resolver: ContentTypeResolver): Route = {
|
def getFromBrowseableDirectories(directories: String*)(implicit renderer: DirectoryRenderer, resolver: ContentTypeResolver): Route = {
|
||||||
directories.map(getFromDirectory).reduceLeft(_ ~ _) ~ listDirectoryContents(directories: _*)
|
directories.map(getFromDirectory).reduceLeft(_ ~ _) ~ listDirectoryContents(directories: _*)
|
||||||
|
|
@ -163,6 +185,8 @@ trait FileAndResourceDirectives {
|
||||||
* Same as "getFromDirectory" except that the file is not fetched from the file system but rather from a
|
* Same as "getFromDirectory" except that the file is not fetched from the file system but rather from a
|
||||||
* "resource directory".
|
* "resource directory".
|
||||||
* If the requested resource is itself a directory or cannot be found or read the Route rejects the request.
|
* If the requested resource is itself a directory or cannot be found or read the Route rejects the request.
|
||||||
|
*
|
||||||
|
* @group fileandresource
|
||||||
*/
|
*/
|
||||||
def getFromResourceDirectory(directoryName: String, classLoader: ClassLoader = defaultClassLoader)(implicit resolver: ContentTypeResolver): Route = {
|
def getFromResourceDirectory(directoryName: String, classLoader: ClassLoader = defaultClassLoader)(implicit resolver: ContentTypeResolver): Route = {
|
||||||
val base = if (directoryName.isEmpty) "" else withTrailingSlash(directoryName)
|
val base = if (directoryName.isEmpty) "" else withTrailingSlash(directoryName)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ import scala.concurrent.Future
|
||||||
import scala.util.{ Failure, Success }
|
import scala.util.{ Failure, Success }
|
||||||
import akka.stream.scaladsl._
|
import akka.stream.scaladsl._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname fileupload File upload directives
|
||||||
|
* @groupprio fileupload 80
|
||||||
|
*/
|
||||||
trait FileUploadDirectives {
|
trait FileUploadDirectives {
|
||||||
|
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
|
|
@ -24,6 +28,8 @@ trait FileUploadDirectives {
|
||||||
* If there is an error writing to disk the request will be failed with the thrown exception, if there is no such
|
* If there is an error writing to disk the request will be failed with the thrown exception, if there is no such
|
||||||
* field the request will be rejected, if there are multiple file parts with the same name, the first one will be
|
* field the request will be rejected, if there are multiple file parts with the same name, the first one will be
|
||||||
* used and the subsequent ones ignored.
|
* used and the subsequent ones ignored.
|
||||||
|
*
|
||||||
|
* @group fileupload
|
||||||
*/
|
*/
|
||||||
def uploadedFile(fieldName: String): Directive1[(FileInfo, File)] =
|
def uploadedFile(fieldName: String): Directive1[(FileInfo, File)] =
|
||||||
extractRequestContext.flatMap { ctx ⇒
|
extractRequestContext.flatMap { ctx ⇒
|
||||||
|
|
@ -55,6 +61,8 @@ trait FileUploadDirectives {
|
||||||
* for streaming the file contents somewhere. If there is no such field the request will be rejected,
|
* for streaming the file contents somewhere. If there is no such field the request will be rejected,
|
||||||
* if there are multiple file parts with the same name, the first one will be used and the subsequent
|
* if there are multiple file parts with the same name, the first one will be used and the subsequent
|
||||||
* ones ignored.
|
* ones ignored.
|
||||||
|
*
|
||||||
|
* @group fileupload
|
||||||
*/
|
*/
|
||||||
def fileUpload(fieldName: String): Directive1[(FileInfo, Source[ByteString, Any])] =
|
def fileUpload(fieldName: String): Directive1[(FileInfo, Source[ByteString, Any])] =
|
||||||
entity(as[Multipart.FormData]).flatMap { formData ⇒
|
entity(as[Multipart.FormData]).flatMap { formData ⇒
|
||||||
|
|
|
||||||
|
|
@ -16,33 +16,47 @@ import scala.collection.immutable
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
import scala.util.{ Failure, Success }
|
import scala.util.{ Failure, Success }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname form Form field directives
|
||||||
|
* @groupprio form 90
|
||||||
|
*/
|
||||||
trait FormFieldDirectives extends ToNameReceptacleEnhancements {
|
trait FormFieldDirectives extends ToNameReceptacleEnhancements {
|
||||||
import FormFieldDirectives._
|
import FormFieldDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts HTTP form fields from the request as a ``Map[String, String]``.
|
* Extracts HTTP form fields from the request as a ``Map[String, String]``.
|
||||||
|
*
|
||||||
|
* @group form
|
||||||
*/
|
*/
|
||||||
def formFieldMap: Directive1[Map[String, String]] = _formFieldMap
|
def formFieldMap: Directive1[Map[String, String]] = _formFieldMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts HTTP form fields from the request as a ``Map[String, List[String]]``.
|
* Extracts HTTP form fields from the request as a ``Map[String, List[String]]``.
|
||||||
|
*
|
||||||
|
* @group form
|
||||||
*/
|
*/
|
||||||
def formFieldMultiMap: Directive1[Map[String, List[String]]] = _formFieldMultiMap
|
def formFieldMultiMap: Directive1[Map[String, List[String]]] = _formFieldMultiMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts HTTP form fields from the request as a ``Seq[(String, String)]``.
|
* Extracts HTTP form fields from the request as a ``Seq[(String, String)]``.
|
||||||
|
*
|
||||||
|
* @group form
|
||||||
*/
|
*/
|
||||||
def formFieldSeq: Directive1[immutable.Seq[(String, String)]] = _formFieldSeq
|
def formFieldSeq: Directive1[immutable.Seq[(String, String)]] = _formFieldSeq
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts an HTTP form field from the request.
|
* Extracts an HTTP form field from the request.
|
||||||
* Rejects the request if the defined form field matcher(s) don't match.
|
* Rejects the request if the defined form field matcher(s) don't match.
|
||||||
|
*
|
||||||
|
* @group form
|
||||||
*/
|
*/
|
||||||
def formField(pdm: FieldMagnet): pdm.Out = pdm()
|
def formField(pdm: FieldMagnet): pdm.Out = pdm()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a number of HTTP form field from the request.
|
* Extracts a number of HTTP form field from the request.
|
||||||
* Rejects the request if the defined form field matcher(s) don't match.
|
* Rejects the request if the defined form field matcher(s) don't match.
|
||||||
|
*
|
||||||
|
* @group form
|
||||||
*/
|
*/
|
||||||
def formFields(pdm: FieldMagnet): pdm.Out = pdm()
|
def formFields(pdm: FieldMagnet): pdm.Out = pdm()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,17 @@ import akka.http.scaladsl.util.FastFuture._
|
||||||
|
|
||||||
// format: OFF
|
// format: OFF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname future Future directives
|
||||||
|
* @groupprio future 100
|
||||||
|
*/
|
||||||
trait FutureDirectives {
|
trait FutureDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Unwraps" a `Future[T]` and runs the inner route after future
|
* "Unwraps" a `Future[T]` and runs the inner route after future
|
||||||
* completion with the future's value as an extraction of type `Try[T]`.
|
* completion with the future's value as an extraction of type `Try[T]`.
|
||||||
|
*
|
||||||
|
* @group future
|
||||||
*/
|
*/
|
||||||
def onComplete[T](future: ⇒ Future[T]): Directive1[Try[T]] =
|
def onComplete[T](future: ⇒ Future[T]): Directive1[Try[T]] =
|
||||||
Directive { inner ⇒ ctx ⇒
|
Directive { inner ⇒ ctx ⇒
|
||||||
|
|
@ -32,6 +38,8 @@ trait FutureDirectives {
|
||||||
* ExceptionHandler.
|
* ExceptionHandler.
|
||||||
* If type `T` is already a Tuple it is directly expanded into the respective
|
* If type `T` is already a Tuple it is directly expanded into the respective
|
||||||
* number of extractions.
|
* number of extractions.
|
||||||
|
*
|
||||||
|
* @group future
|
||||||
*/
|
*/
|
||||||
def onSuccess(magnet: OnSuccessMagnet): Directive[magnet.Out] = magnet.directive
|
def onSuccess(magnet: OnSuccessMagnet): Directive[magnet.Out] = magnet.directive
|
||||||
|
|
||||||
|
|
@ -41,6 +49,8 @@ trait FutureDirectives {
|
||||||
* If the future succeeds the request is completed using the values marshaller
|
* If the future succeeds the request is completed using the values marshaller
|
||||||
* (This directive therefore requires a marshaller for the futures type to be
|
* (This directive therefore requires a marshaller for the futures type to be
|
||||||
* implicitly available.)
|
* implicitly available.)
|
||||||
|
*
|
||||||
|
* @group future
|
||||||
*/
|
*/
|
||||||
def completeOrRecoverWith(magnet: CompleteOrRecoverWithMagnet): Directive1[Throwable] = magnet.directive
|
def completeOrRecoverWith(magnet: CompleteOrRecoverWithMagnet): Directive1[Throwable] = magnet.directive
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ import akka.http.scaladsl.server.util.ClassMagnet
|
||||||
import akka.http.scaladsl.model._
|
import akka.http.scaladsl.model._
|
||||||
import akka.http.impl.util._
|
import akka.http.impl.util._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname header Header directives
|
||||||
|
* @groupprio header 110
|
||||||
|
*/
|
||||||
trait HeaderDirectives {
|
trait HeaderDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
import RouteDirectives._
|
import RouteDirectives._
|
||||||
|
|
@ -24,6 +28,8 @@ trait HeaderDirectives {
|
||||||
* Extracts an HTTP header value using the given function. If the function result is undefined for all headers the
|
* Extracts an HTTP header value using the given function. If the function result is undefined for all headers the
|
||||||
* request is rejected with an empty rejection set. If the given function throws an exception the request is rejected
|
* request is rejected with an empty rejection set. If the given function throws an exception the request is rejected
|
||||||
* with a [[akka.http.scaladsl.server.MalformedHeaderRejection]].
|
* with a [[akka.http.scaladsl.server.MalformedHeaderRejection]].
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def headerValue[T](f: HttpHeader ⇒ Option[T]): Directive1[T] = {
|
def headerValue[T](f: HttpHeader ⇒ Option[T]): Directive1[T] = {
|
||||||
val protectedF: HttpHeader ⇒ Option[Either[Rejection, T]] = header ⇒
|
val protectedF: HttpHeader ⇒ Option[Either[Rejection, T]] = header ⇒
|
||||||
|
|
@ -42,18 +48,24 @@ trait HeaderDirectives {
|
||||||
/**
|
/**
|
||||||
* Extracts an HTTP header value using the given partial function. If the function is undefined for all headers the
|
* Extracts an HTTP header value using the given partial function. If the function is undefined for all headers the
|
||||||
* request is rejected with an empty rejection set.
|
* request is rejected with an empty rejection set.
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def headerValuePF[T](pf: PartialFunction[HttpHeader, T]): Directive1[T] = headerValue(pf.lift)
|
def headerValuePF[T](pf: PartialFunction[HttpHeader, T]): Directive1[T] = headerValue(pf.lift)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the value of the first HTTP request header with the given name.
|
* Extracts the value of the first HTTP request header with the given name.
|
||||||
* If no header with a matching name is found the request is rejected with a [[akka.http.scaladsl.server.MissingHeaderRejection]].
|
* If no header with a matching name is found the request is rejected with a [[akka.http.scaladsl.server.MissingHeaderRejection]].
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def headerValueByName(headerName: Symbol): Directive1[String] = headerValueByName(headerName.name)
|
def headerValueByName(headerName: Symbol): Directive1[String] = headerValueByName(headerName.name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the value of the HTTP request header with the given name.
|
* Extracts the value of the HTTP request header with the given name.
|
||||||
* If no header with a matching name is found the request is rejected with a [[akka.http.scaladsl.server.MissingHeaderRejection]].
|
* If no header with a matching name is found the request is rejected with a [[akka.http.scaladsl.server.MissingHeaderRejection]].
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def headerValueByName(headerName: String): Directive1[String] =
|
def headerValueByName(headerName: String): Directive1[String] =
|
||||||
headerValue(optionalValue(headerName.toLowerCase)) | reject(MissingHeaderRejection(headerName))
|
headerValue(optionalValue(headerName.toLowerCase)) | reject(MissingHeaderRejection(headerName))
|
||||||
|
|
@ -64,6 +76,8 @@ trait HeaderDirectives {
|
||||||
*
|
*
|
||||||
* Custom headers will only be matched by this directive if they extend [[ModeledCustomHeader]]
|
* Custom headers will only be matched by this directive if they extend [[ModeledCustomHeader]]
|
||||||
* and provide a companion extending [[ModeledCustomHeaderCompanion]].
|
* and provide a companion extending [[ModeledCustomHeaderCompanion]].
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def headerValueByType[T](magnet: HeaderMagnet[T]): Directive1[T] =
|
def headerValueByType[T](magnet: HeaderMagnet[T]): Directive1[T] =
|
||||||
headerValuePF(magnet.extractPF) | reject(MissingHeaderRejection(magnet.runtimeClass.getSimpleName))
|
headerValuePF(magnet.extractPF) | reject(MissingHeaderRejection(magnet.runtimeClass.getSimpleName))
|
||||||
|
|
@ -73,6 +87,8 @@ trait HeaderDirectives {
|
||||||
* Extracts an optional HTTP header value using the given function.
|
* Extracts an optional HTTP header value using the given function.
|
||||||
* If the given function throws an exception the request is rejected
|
* If the given function throws an exception the request is rejected
|
||||||
* with a [[akka.http.scaladsl.server.MalformedHeaderRejection]].
|
* with a [[akka.http.scaladsl.server.MalformedHeaderRejection]].
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def optionalHeaderValue[T](f: HttpHeader ⇒ Option[T]): Directive1[Option[T]] =
|
def optionalHeaderValue[T](f: HttpHeader ⇒ Option[T]): Directive1[Option[T]] =
|
||||||
headerValue(f).map(Some(_): Option[T]).recoverPF {
|
headerValue(f).map(Some(_): Option[T]).recoverPF {
|
||||||
|
|
@ -84,18 +100,24 @@ trait HeaderDirectives {
|
||||||
* Extracts an optional HTTP header value using the given partial function.
|
* Extracts an optional HTTP header value using the given partial function.
|
||||||
* If the given function throws an exception the request is rejected
|
* If the given function throws an exception the request is rejected
|
||||||
* with a [[akka.http.scaladsl.server.MalformedHeaderRejection]].
|
* with a [[akka.http.scaladsl.server.MalformedHeaderRejection]].
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def optionalHeaderValuePF[T](pf: PartialFunction[HttpHeader, T]): Directive1[Option[T]] =
|
def optionalHeaderValuePF[T](pf: PartialFunction[HttpHeader, T]): Directive1[Option[T]] =
|
||||||
optionalHeaderValue(pf.lift)
|
optionalHeaderValue(pf.lift)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the value of the optional HTTP request header with the given name.
|
* Extracts the value of the optional HTTP request header with the given name.
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def optionalHeaderValueByName(headerName: Symbol): Directive1[Option[String]] =
|
def optionalHeaderValueByName(headerName: Symbol): Directive1[Option[String]] =
|
||||||
optionalHeaderValueByName(headerName.name)
|
optionalHeaderValueByName(headerName.name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the value of the optional HTTP request header with the given name.
|
* Extracts the value of the optional HTTP request header with the given name.
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def optionalHeaderValueByName(headerName: String): Directive1[Option[String]] = {
|
def optionalHeaderValueByName(headerName: String): Directive1[Option[String]] = {
|
||||||
val lowerCaseName = headerName.toLowerCase
|
val lowerCaseName = headerName.toLowerCase
|
||||||
|
|
@ -109,6 +131,8 @@ trait HeaderDirectives {
|
||||||
*
|
*
|
||||||
* Custom headers will only be matched by this directive if they extend [[ModeledCustomHeader]]
|
* Custom headers will only be matched by this directive if they extend [[ModeledCustomHeader]]
|
||||||
* and provide a companion extending [[ModeledCustomHeaderCompanion]].
|
* and provide a companion extending [[ModeledCustomHeaderCompanion]].
|
||||||
|
*
|
||||||
|
* @group header
|
||||||
*/
|
*/
|
||||||
def optionalHeaderValueByType[T <: HttpHeader](magnet: HeaderMagnet[T]): Directive1[Option[T]] =
|
def optionalHeaderValueByType[T <: HttpHeader](magnet: HeaderMagnet[T]): Directive1[Option[T]] =
|
||||||
optionalHeaderValuePF(magnet.extractPF)
|
optionalHeaderValuePF(magnet.extractPF)
|
||||||
|
|
@ -156,4 +180,4 @@ trait LowPriorityHeaderMagnetImplicits {
|
||||||
val runtimeClass: Class[T] = tag.runtimeClass.asInstanceOf[Class[T]]
|
val runtimeClass: Class[T] = tag.runtimeClass.asInstanceOf[Class[T]]
|
||||||
val extractPF: PartialFunction[Any, T] = { case x: T ⇒ x }
|
val extractPF: PartialFunction[Any, T] = { case x: T ⇒ x }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,33 @@ package directives
|
||||||
import scala.util.matching.Regex
|
import scala.util.matching.Regex
|
||||||
import akka.http.impl.util._
|
import akka.http.impl.util._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname host Host directives
|
||||||
|
* @groupprio host 110
|
||||||
|
*/
|
||||||
trait HostDirectives {
|
trait HostDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
import RouteDirectives._
|
import RouteDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the hostname part of the Host request header value.
|
* Extracts the hostname part of the Host request header value.
|
||||||
|
*
|
||||||
|
* @group host
|
||||||
*/
|
*/
|
||||||
def extractHost: Directive1[String] = HostDirectives._extractHost
|
def extractHost: Directive1[String] = HostDirectives._extractHost
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all requests with a host name different from the given ones.
|
* Rejects all requests with a host name different from the given ones.
|
||||||
|
*
|
||||||
|
* @group host
|
||||||
*/
|
*/
|
||||||
def host(hostNames: String*): Directive0 = host(hostNames.contains(_))
|
def host(hostNames: String*): Directive0 = host(hostNames.contains(_))
|
||||||
|
|
||||||
//#require-host
|
//#require-host
|
||||||
/**
|
/**
|
||||||
* Rejects all requests for whose host name the given predicate function returns false.
|
* Rejects all requests for whose host name the given predicate function returns false.
|
||||||
|
*
|
||||||
|
* @group host
|
||||||
*/
|
*/
|
||||||
def host(predicate: String ⇒ Boolean): Directive0 = extractHost.require(predicate)
|
def host(predicate: String ⇒ Boolean): Directive0 = extractHost.require(predicate)
|
||||||
//#
|
//#
|
||||||
|
|
@ -34,6 +44,8 @@ trait HostDirectives {
|
||||||
* For all matching requests the prefix string matching the regex is extracted and passed to the inner route.
|
* For all matching requests the prefix string matching the regex is extracted and passed to the inner route.
|
||||||
* If the regex contains a capturing group only the string matched by this group is extracted.
|
* If the regex contains a capturing group only the string matched by this group is extracted.
|
||||||
* If the regex contains more than one capturing group an IllegalArgumentException is thrown.
|
* If the regex contains more than one capturing group an IllegalArgumentException is thrown.
|
||||||
|
*
|
||||||
|
* @group host
|
||||||
*/
|
*/
|
||||||
def host(regex: Regex): Directive1[String] = {
|
def host(regex: Regex): Directive1[String] = {
|
||||||
def forFunc(regexMatch: String ⇒ Option[String]): Directive1[String] = {
|
def forFunc(regexMatch: String ⇒ Option[String]): Directive1[String] = {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ import akka.http.scaladsl.marshalling.ToResponseMarshaller
|
||||||
import akka.http.scaladsl.unmarshalling.{ Unmarshaller, FromRequestUnmarshaller }
|
import akka.http.scaladsl.unmarshalling.{ Unmarshaller, FromRequestUnmarshaller }
|
||||||
import akka.http.impl.util._
|
import akka.http.impl.util._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname marshalling Marshalling directives
|
||||||
|
* @groupprio marshalling 120
|
||||||
|
*/
|
||||||
trait MarshallingDirectives {
|
trait MarshallingDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
import FutureDirectives._
|
import FutureDirectives._
|
||||||
|
|
@ -20,6 +24,8 @@ trait MarshallingDirectives {
|
||||||
* Unmarshalls the requests entity to the given type passes it to its inner Route.
|
* Unmarshalls the requests entity to the given type passes it to its inner Route.
|
||||||
* If there is a problem with unmarshalling the request is rejected with the [[Rejection]]
|
* If there is a problem with unmarshalling the request is rejected with the [[Rejection]]
|
||||||
* produced by the unmarshaller.
|
* produced by the unmarshaller.
|
||||||
|
*
|
||||||
|
* @group marshalling
|
||||||
*/
|
*/
|
||||||
def entity[T](um: FromRequestUnmarshaller[T]): Directive1[T] =
|
def entity[T](um: FromRequestUnmarshaller[T]): Directive1[T] =
|
||||||
extractRequestContext.flatMap[Tuple1[T]] { ctx ⇒
|
extractRequestContext.flatMap[Tuple1[T]] { ctx ⇒
|
||||||
|
|
@ -36,12 +42,16 @@ trait MarshallingDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the in-scope [[FromRequestUnmarshaller]] for the given type.
|
* Returns the in-scope [[FromRequestUnmarshaller]] for the given type.
|
||||||
|
*
|
||||||
|
* @group marshalling
|
||||||
*/
|
*/
|
||||||
def as[T](implicit um: FromRequestUnmarshaller[T]) = um
|
def as[T](implicit um: FromRequestUnmarshaller[T]) = um
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the marshaller for the given type to produce a completion function that is passed to its inner function.
|
* Uses the marshaller for the given type to produce a completion function that is passed to its inner function.
|
||||||
* You can use it do decouple marshaller resolution from request completion.
|
* You can use it do decouple marshaller resolution from request completion.
|
||||||
|
*
|
||||||
|
* @group marshalling
|
||||||
*/
|
*/
|
||||||
def completeWith[T](marshaller: ToResponseMarshaller[T])(inner: (T ⇒ Unit) ⇒ Unit): Route =
|
def completeWith[T](marshaller: ToResponseMarshaller[T])(inner: (T ⇒ Unit) ⇒ Unit): Route =
|
||||||
extractRequestContext { ctx ⇒
|
extractRequestContext { ctx ⇒
|
||||||
|
|
@ -55,12 +65,16 @@ trait MarshallingDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the in-scope Marshaller for the given type.
|
* Returns the in-scope Marshaller for the given type.
|
||||||
|
*
|
||||||
|
* @group marshalling
|
||||||
*/
|
*/
|
||||||
def instanceOf[T](implicit m: ToResponseMarshaller[T]): ToResponseMarshaller[T] = m
|
def instanceOf[T](implicit m: ToResponseMarshaller[T]): ToResponseMarshaller[T] = m
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completes the request using the given function. The input to the function is produced with the in-scope
|
* Completes the request using the given function. The input to the function is produced with the in-scope
|
||||||
* entity unmarshaller and the result value of the function is marshalled with the in-scope marshaller.
|
* entity unmarshaller and the result value of the function is marshalled with the in-scope marshaller.
|
||||||
|
*
|
||||||
|
* @group marshalling
|
||||||
*/
|
*/
|
||||||
def handleWith[A, B](f: A ⇒ B)(implicit um: FromRequestUnmarshaller[A], m: ToResponseMarshaller[B]): Route =
|
def handleWith[A, B](f: A ⇒ B)(implicit um: FromRequestUnmarshaller[A], m: ToResponseMarshaller[B]): Route =
|
||||||
entity(um) { a ⇒ complete(f(a)) }
|
entity(um) { a ⇒ complete(f(a)) }
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ package directives
|
||||||
import akka.http.scaladsl.model.{ StatusCodes, HttpMethod }
|
import akka.http.scaladsl.model.{ StatusCodes, HttpMethod }
|
||||||
import akka.http.scaladsl.model.HttpMethods._
|
import akka.http.scaladsl.model.HttpMethods._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname method Method directives
|
||||||
|
* @groupprio method 130
|
||||||
|
*/
|
||||||
trait MethodDirectives {
|
trait MethodDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
import RouteDirectives._
|
import RouteDirectives._
|
||||||
|
|
@ -16,47 +20,65 @@ trait MethodDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all non-DELETE requests.
|
* Rejects all non-DELETE requests.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def delete: Directive0 = _delete
|
def delete: Directive0 = _delete
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all non-GET requests.
|
* Rejects all non-GET requests.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def get: Directive0 = _get
|
def get: Directive0 = _get
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all non-HEAD requests.
|
* Rejects all non-HEAD requests.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def head: Directive0 = _head
|
def head: Directive0 = _head
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all non-OPTIONS requests.
|
* Rejects all non-OPTIONS requests.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def options: Directive0 = _options
|
def options: Directive0 = _options
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all non-PATCH requests.
|
* Rejects all non-PATCH requests.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def patch: Directive0 = _patch
|
def patch: Directive0 = _patch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all non-POST requests.
|
* Rejects all non-POST requests.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def post: Directive0 = _post
|
def post: Directive0 = _post
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all non-PUT requests.
|
* Rejects all non-PUT requests.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def put: Directive0 = _put
|
def put: Directive0 = _put
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the request method.
|
* Extracts the request method.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def extractMethod: Directive1[HttpMethod] = _extractMethod
|
def extractMethod: Directive1[HttpMethod] = _extractMethod
|
||||||
|
|
||||||
//#method
|
//#method
|
||||||
/**
|
/**
|
||||||
* Rejects all requests whose HTTP method does not match the given one.
|
* Rejects all requests whose HTTP method does not match the given one.
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def method(httpMethod: HttpMethod): Directive0 =
|
def method(httpMethod: HttpMethod): Directive0 =
|
||||||
extractMethod.flatMap[Unit] {
|
extractMethod.flatMap[Unit] {
|
||||||
|
|
@ -73,6 +95,8 @@ trait MethodDirectives {
|
||||||
* This directive is useful for:
|
* This directive is useful for:
|
||||||
* - Use in combination with JSONP (JSONP only supports GET)
|
* - Use in combination with JSONP (JSONP only supports GET)
|
||||||
* - Supporting older browsers that lack support for certain HTTP methods. E.g. IE8 does not support PATCH
|
* - Supporting older browsers that lack support for certain HTTP methods. E.g. IE8 does not support PATCH
|
||||||
|
*
|
||||||
|
* @group method
|
||||||
*/
|
*/
|
||||||
def overrideMethodWithParameter(paramName: String): Directive0 =
|
def overrideMethodWithParameter(paramName: String): Directive0 =
|
||||||
parameter(paramName?) flatMap {
|
parameter(paramName?) flatMap {
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,18 @@ package directives
|
||||||
import akka.http.scaladsl.model._
|
import akka.http.scaladsl.model._
|
||||||
import headers._
|
import headers._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname misc Miscellaneous directives
|
||||||
|
* @groupprio misc 140
|
||||||
|
*/
|
||||||
trait MiscDirectives {
|
trait MiscDirectives {
|
||||||
import RouteDirectives._
|
import RouteDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the given condition before running its inner route.
|
* Checks the given condition before running its inner route.
|
||||||
* If the condition fails the route is rejected with a [[ValidationRejection]].
|
* If the condition fails the route is rejected with a [[ValidationRejection]].
|
||||||
|
*
|
||||||
|
* @group misc
|
||||||
*/
|
*/
|
||||||
def validate(check: ⇒ Boolean, errorMsg: String): Directive0 =
|
def validate(check: ⇒ Boolean, errorMsg: String): Directive0 =
|
||||||
Directive { inner ⇒ if (check) inner(()) else reject(ValidationRejection(errorMsg)) }
|
Directive { inner ⇒ if (check) inner(()) else reject(ValidationRejection(errorMsg)) }
|
||||||
|
|
@ -21,17 +27,23 @@ trait MiscDirectives {
|
||||||
/**
|
/**
|
||||||
* Extracts the client's IP from either the X-Forwarded-For, Remote-Address or X-Real-IP header
|
* Extracts the client's IP from either the X-Forwarded-For, Remote-Address or X-Real-IP header
|
||||||
* (in that order of priority).
|
* (in that order of priority).
|
||||||
|
*
|
||||||
|
* @group misc
|
||||||
*/
|
*/
|
||||||
def extractClientIP: Directive1[RemoteAddress] = MiscDirectives._extractClientIP
|
def extractClientIP: Directive1[RemoteAddress] = MiscDirectives._extractClientIP
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects if the request entity is non-empty.
|
* Rejects if the request entity is non-empty.
|
||||||
|
*
|
||||||
|
* @group misc
|
||||||
*/
|
*/
|
||||||
def requestEntityEmpty: Directive0 = MiscDirectives._requestEntityEmpty
|
def requestEntityEmpty: Directive0 = MiscDirectives._requestEntityEmpty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects with a [[RequestEntityExpectedRejection]] if the request entity is empty.
|
* Rejects with a [[RequestEntityExpectedRejection]] if the request entity is empty.
|
||||||
* Non-empty requests are passed on unchanged to the inner route.
|
* Non-empty requests are passed on unchanged to the inner route.
|
||||||
|
*
|
||||||
|
* @group misc
|
||||||
*/
|
*/
|
||||||
def requestEntityPresent: Directive0 = MiscDirectives._requestEntityPresent
|
def requestEntityPresent: Directive0 = MiscDirectives._requestEntityPresent
|
||||||
|
|
||||||
|
|
@ -39,6 +51,8 @@ trait MiscDirectives {
|
||||||
* Converts responses with an empty entity into (empty) rejections.
|
* Converts responses with an empty entity into (empty) rejections.
|
||||||
* This way you can, for example, have the marshalling of a ''None'' option
|
* This way you can, for example, have the marshalling of a ''None'' option
|
||||||
* be treated as if the request could not be matched.
|
* be treated as if the request could not be matched.
|
||||||
|
*
|
||||||
|
* @group misc
|
||||||
*/
|
*/
|
||||||
def rejectEmptyResponse: Directive0 = MiscDirectives._rejectEmptyResponse
|
def rejectEmptyResponse: Directive0 = MiscDirectives._rejectEmptyResponse
|
||||||
|
|
||||||
|
|
@ -50,6 +64,8 @@ trait MiscDirectives {
|
||||||
* If there are several best language alternatives that the client
|
* If there are several best language alternatives that the client
|
||||||
* has equal preference for (even if this preference is zero!)
|
* has equal preference for (even if this preference is zero!)
|
||||||
* the order of the arguments is used as a tie breaker (First one wins).
|
* the order of the arguments is used as a tie breaker (First one wins).
|
||||||
|
*
|
||||||
|
* @group misc
|
||||||
*/
|
*/
|
||||||
def selectPreferredLanguage(first: Language, more: Language*): Directive1[Language] =
|
def selectPreferredLanguage(first: Language, more: Language*): Directive1[Language] =
|
||||||
BasicDirectives.extractRequest.map { request ⇒
|
BasicDirectives.extractRequest.map { request ⇒
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,31 @@ import scala.util.{ Failure, Success }
|
||||||
import akka.http.scaladsl.common._
|
import akka.http.scaladsl.common._
|
||||||
import akka.http.impl.util._
|
import akka.http.impl.util._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname param Parameter directives
|
||||||
|
* @groupprio param 150
|
||||||
|
*/
|
||||||
trait ParameterDirectives extends ToNameReceptacleEnhancements {
|
trait ParameterDirectives extends ToNameReceptacleEnhancements {
|
||||||
import ParameterDirectives._
|
import ParameterDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the request's query parameters as a `Map[String, String]`.
|
* Extracts the request's query parameters as a `Map[String, String]`.
|
||||||
|
*
|
||||||
|
* @group param
|
||||||
*/
|
*/
|
||||||
def parameterMap: Directive1[Map[String, String]] = _parameterMap
|
def parameterMap: Directive1[Map[String, String]] = _parameterMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the request's query parameters as a `Map[String, List[String]]`.
|
* Extracts the request's query parameters as a `Map[String, List[String]]`.
|
||||||
|
*
|
||||||
|
* @group param
|
||||||
*/
|
*/
|
||||||
def parameterMultiMap: Directive1[Map[String, List[String]]] = _parameterMultiMap
|
def parameterMultiMap: Directive1[Map[String, List[String]]] = _parameterMultiMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the request's query parameters as a `Seq[(String, String)]`.
|
* Extracts the request's query parameters as a `Seq[(String, String)]`.
|
||||||
|
*
|
||||||
|
* @group param
|
||||||
*/
|
*/
|
||||||
def parameterSeq: Directive1[immutable.Seq[(String, String)]] = _parameterSeq
|
def parameterSeq: Directive1[immutable.Seq[(String, String)]] = _parameterSeq
|
||||||
|
|
||||||
|
|
@ -37,6 +47,8 @@ trait ParameterDirectives extends ToNameReceptacleEnhancements {
|
||||||
* "too many arguments for method parameter" or "type mismatch" error.
|
* "too many arguments for method parameter" or "type mismatch" error.
|
||||||
*
|
*
|
||||||
* As a workaround add an `import ParameterDirectives.ParamMagnet` or use Scala 2.11.x.
|
* As a workaround add an `import ParameterDirectives.ParamMagnet` or use Scala 2.11.x.
|
||||||
|
*
|
||||||
|
* @group param
|
||||||
*/
|
*/
|
||||||
def parameter(pdm: ParamMagnet): pdm.Out = pdm()
|
def parameter(pdm: ParamMagnet): pdm.Out = pdm()
|
||||||
|
|
||||||
|
|
@ -48,6 +60,8 @@ trait ParameterDirectives extends ToNameReceptacleEnhancements {
|
||||||
* "too many arguments for method parameters" or "type mismatch" error.
|
* "too many arguments for method parameters" or "type mismatch" error.
|
||||||
*
|
*
|
||||||
* As a workaround add an `import ParameterDirectives.ParamMagnet` or use Scala 2.11.x.
|
* As a workaround add an `import ParameterDirectives.ParamMagnet` or use Scala 2.11.x.
|
||||||
|
*
|
||||||
|
* @group param
|
||||||
*/
|
*/
|
||||||
def parameters(pdm: ParamMagnet): pdm.Out = pdm()
|
def parameters(pdm: ParamMagnet): pdm.Out = pdm()
|
||||||
|
|
||||||
|
|
@ -170,4 +184,4 @@ object ParameterDirectives extends ParameterDirectives {
|
||||||
at[Directive[TA], P] { (a, t) ⇒ a & pdef(t) }
|
at[Directive[TA], P] { (a, t) ⇒ a & pdef(t) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ import akka.http.scaladsl.common.ToNameReceptacleEnhancements
|
||||||
import akka.http.scaladsl.model.StatusCodes
|
import akka.http.scaladsl.model.StatusCodes
|
||||||
import akka.http.scaladsl.model.Uri.Path
|
import akka.http.scaladsl.model.Uri.Path
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname path Path directives
|
||||||
|
* @groupprio path 170
|
||||||
|
*/
|
||||||
trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction with ToNameReceptacleEnhancements {
|
trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction with ToNameReceptacleEnhancements {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
import RouteDirectives._
|
import RouteDirectives._
|
||||||
|
|
@ -18,6 +22,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* Applies the given [[PathMatcher]] to the remaining unmatched path after consuming a leading slash.
|
* Applies the given [[PathMatcher]] to the remaining unmatched path after consuming a leading slash.
|
||||||
* The matcher has to match the remaining path completely.
|
* The matcher has to match the remaining path completely.
|
||||||
* If matched the value extracted by the [[PathMatcher]] is extracted on the directive level.
|
* If matched the value extracted by the [[PathMatcher]] is extracted on the directive level.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def path[L](pm: PathMatcher[L]): Directive[L] = pathPrefix(pm ~ PathEnd)
|
def path[L](pm: PathMatcher[L]): Directive[L] = pathPrefix(pm ~ PathEnd)
|
||||||
|
|
||||||
|
|
@ -25,6 +31,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* Applies the given [[PathMatcher]] to a prefix of the remaining unmatched path after consuming a leading slash.
|
* Applies the given [[PathMatcher]] to a prefix of the remaining unmatched path after consuming a leading slash.
|
||||||
* The matcher has to match a prefix of the remaining path.
|
* The matcher has to match a prefix of the remaining path.
|
||||||
* If matched the value extracted by the PathMatcher is extracted on the directive level.
|
* If matched the value extracted by the PathMatcher is extracted on the directive level.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def pathPrefix[L](pm: PathMatcher[L]): Directive[L] = rawPathPrefix(Slash ~ pm)
|
def pathPrefix[L](pm: PathMatcher[L]): Directive[L] = rawPathPrefix(Slash ~ pm)
|
||||||
|
|
||||||
|
|
@ -33,6 +41,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* [[RequestContext]] (i.e. without implicitly consuming a leading slash).
|
* [[RequestContext]] (i.e. without implicitly consuming a leading slash).
|
||||||
* The matcher has to match a prefix of the remaining path.
|
* The matcher has to match a prefix of the remaining path.
|
||||||
* If matched the value extracted by the PathMatcher is extracted on the directive level.
|
* If matched the value extracted by the PathMatcher is extracted on the directive level.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def rawPathPrefix[L](pm: PathMatcher[L]): Directive[L] = {
|
def rawPathPrefix[L](pm: PathMatcher[L]): Directive[L] = {
|
||||||
implicit val LIsTuple = pm.ev
|
implicit val LIsTuple = pm.ev
|
||||||
|
|
@ -45,6 +55,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
/**
|
/**
|
||||||
* Checks whether the unmatchedPath of the [[RequestContext]] has a prefix matched by the
|
* Checks whether the unmatchedPath of the [[RequestContext]] has a prefix matched by the
|
||||||
* given PathMatcher. In analogy to the `pathPrefix` directive a leading slash is implied.
|
* given PathMatcher. In analogy to the `pathPrefix` directive a leading slash is implied.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def pathPrefixTest[L](pm: PathMatcher[L]): Directive[L] = rawPathPrefixTest(Slash ~ pm)
|
def pathPrefixTest[L](pm: PathMatcher[L]): Directive[L] = rawPathPrefixTest(Slash ~ pm)
|
||||||
|
|
||||||
|
|
@ -52,6 +64,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* Checks whether the unmatchedPath of the [[RequestContext]] has a prefix matched by the
|
* Checks whether the unmatchedPath of the [[RequestContext]] has a prefix matched by the
|
||||||
* given PathMatcher. However, as opposed to the `pathPrefix` directive the matched path is not
|
* given PathMatcher. However, as opposed to the `pathPrefix` directive the matched path is not
|
||||||
* actually "consumed".
|
* actually "consumed".
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def rawPathPrefixTest[L](pm: PathMatcher[L]): Directive[L] = {
|
def rawPathPrefixTest[L](pm: PathMatcher[L]): Directive[L] = {
|
||||||
implicit val LIsTuple = pm.ev
|
implicit val LIsTuple = pm.ev
|
||||||
|
|
@ -66,6 +80,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* If matched the value extracted by the [[PathMatcher]] is extracted and the matched parts of the path are consumed.
|
* If matched the value extracted by the [[PathMatcher]] is extracted and the matched parts of the path are consumed.
|
||||||
* Note that, for efficiency reasons, the given [[PathMatcher]] must match the desired suffix in reversed-segment
|
* Note that, for efficiency reasons, the given [[PathMatcher]] must match the desired suffix in reversed-segment
|
||||||
* order, i.e. `pathSuffix("baz" / "bar")` would match `/foo/bar/baz`!
|
* order, i.e. `pathSuffix("baz" / "bar")` would match `/foo/bar/baz`!
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def pathSuffix[L](pm: PathMatcher[L]): Directive[L] = {
|
def pathSuffix[L](pm: PathMatcher[L]): Directive[L] = {
|
||||||
implicit val LIsTuple = pm.ev
|
implicit val LIsTuple = pm.ev
|
||||||
|
|
@ -81,6 +97,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* actually "consumed".
|
* actually "consumed".
|
||||||
* Note that, for efficiency reasons, the given PathMatcher must match the desired suffix in reversed-segment
|
* Note that, for efficiency reasons, the given PathMatcher must match the desired suffix in reversed-segment
|
||||||
* order, i.e. `pathSuffixTest("baz" / "bar")` would match `/foo/bar/baz`!
|
* order, i.e. `pathSuffixTest("baz" / "bar")` would match `/foo/bar/baz`!
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def pathSuffixTest[L](pm: PathMatcher[L]): Directive[L] = {
|
def pathSuffixTest[L](pm: PathMatcher[L]): Directive[L] = {
|
||||||
implicit val LIsTuple = pm.ev
|
implicit val LIsTuple = pm.ev
|
||||||
|
|
@ -94,6 +112,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* Rejects the request if the unmatchedPath of the [[RequestContext]] is non-empty,
|
* Rejects the request if the unmatchedPath of the [[RequestContext]] is non-empty,
|
||||||
* or said differently: only passes on the request to its inner route if the request path
|
* or said differently: only passes on the request to its inner route if the request path
|
||||||
* has been matched completely.
|
* has been matched completely.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def pathEnd: Directive0 = rawPathPrefix(PathEnd)
|
def pathEnd: Directive0 = rawPathPrefix(PathEnd)
|
||||||
|
|
||||||
|
|
@ -124,12 +144,16 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
*
|
*
|
||||||
* For further information, refer to:
|
* For further information, refer to:
|
||||||
* @see [[http://googlewebmastercentral.blogspot.de/2010/04/to-slash-or-not-to-slash.html]]
|
* @see [[http://googlewebmastercentral.blogspot.de/2010/04/to-slash-or-not-to-slash.html]]
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def pathEndOrSingleSlash: Directive0 = rawPathPrefix(Slash.? ~ PathEnd)
|
def pathEndOrSingleSlash: Directive0 = rawPathPrefix(Slash.? ~ PathEnd)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only passes on the request to its inner route if the request path
|
* Only passes on the request to its inner route if the request path
|
||||||
* consists of exactly one remaining slash.
|
* consists of exactly one remaining slash.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def pathSingleSlash: Directive0 = pathPrefix(PathEnd)
|
def pathSingleSlash: Directive0 = pathPrefix(PathEnd)
|
||||||
|
|
||||||
|
|
@ -137,6 +161,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* If the request path doesn't end with a slash, redirect to the same uri with trailing slash in the path.
|
* If the request path doesn't end with a slash, redirect to the same uri with trailing slash in the path.
|
||||||
*
|
*
|
||||||
* '''Caveat''': [[path]] without trailing slash and [[pathEnd]] directives will not match inside of this directive.
|
* '''Caveat''': [[path]] without trailing slash and [[pathEnd]] directives will not match inside of this directive.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def redirectToTrailingSlashIfMissing(redirectionType: StatusCodes.Redirection): Directive0 =
|
def redirectToTrailingSlashIfMissing(redirectionType: StatusCodes.Redirection): Directive0 =
|
||||||
extractUri.flatMap { uri ⇒
|
extractUri.flatMap { uri ⇒
|
||||||
|
|
@ -152,6 +178,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w
|
||||||
* If the request path ends with a slash, redirect to the same uri without trailing slash in the path.
|
* If the request path ends with a slash, redirect to the same uri without trailing slash in the path.
|
||||||
*
|
*
|
||||||
* '''Caveat''': [[pathSingleSlash]] directive will not match inside of this directive.
|
* '''Caveat''': [[pathSingleSlash]] directive will not match inside of this directive.
|
||||||
|
*
|
||||||
|
* @group path
|
||||||
*/
|
*/
|
||||||
def redirectToNoTrailingSlashIfPresent(redirectionType: StatusCodes.Redirection): Directive0 =
|
def redirectToNoTrailingSlashIfPresent(redirectionType: StatusCodes.Redirection): Directive0 =
|
||||||
extractUri.flatMap { uri ⇒
|
extractUri.flatMap { uri ⇒
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ import akka.util.ByteString
|
||||||
import akka.stream.SourceShape
|
import akka.stream.SourceShape
|
||||||
import akka.stream.OverflowStrategy
|
import akka.stream.OverflowStrategy
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname range Range directives
|
||||||
|
* @groupprio range 180
|
||||||
|
*/
|
||||||
trait RangeDirectives {
|
trait RangeDirectives {
|
||||||
import akka.http.scaladsl.server.directives.BasicDirectives._
|
import akka.http.scaladsl.server.directives.BasicDirectives._
|
||||||
import akka.http.scaladsl.server.directives.RouteDirectives._
|
import akka.http.scaladsl.server.directives.RouteDirectives._
|
||||||
|
|
@ -33,6 +37,8 @@ trait RangeDirectives {
|
||||||
* on a higher level in your route structure in order to function correctly.
|
* on a higher level in your route structure in order to function correctly.
|
||||||
*
|
*
|
||||||
* @see [[https://tools.ietf.org/html/rfc7233]]
|
* @see [[https://tools.ietf.org/html/rfc7233]]
|
||||||
|
*
|
||||||
|
* @group range
|
||||||
*/
|
*/
|
||||||
def withRangeSupport: Directive0 =
|
def withRangeSupport: Directive0 =
|
||||||
extractRequestContext.flatMap { ctx ⇒
|
extractRequestContext.flatMap { ctx ⇒
|
||||||
|
|
|
||||||
|
|
@ -4,28 +4,40 @@ package directives
|
||||||
import akka.http.scaladsl.model._
|
import akka.http.scaladsl.model._
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname response Response directives
|
||||||
|
* @groupprio response 190
|
||||||
|
*/
|
||||||
trait RespondWithDirectives {
|
trait RespondWithDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unconditionally adds the given response header to all HTTP responses of its inner Route.
|
* Unconditionally adds the given response header to all HTTP responses of its inner Route.
|
||||||
|
*
|
||||||
|
* @group response
|
||||||
*/
|
*/
|
||||||
def respondWithHeader(responseHeader: HttpHeader): Directive0 = respondWithHeaders(responseHeader)
|
def respondWithHeader(responseHeader: HttpHeader): Directive0 = respondWithHeaders(responseHeader)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given response header to all HTTP responses of its inner Route,
|
* Adds the given response header to all HTTP responses of its inner Route,
|
||||||
* if the response from the inner Route doesn't already contain a header with the same name.
|
* if the response from the inner Route doesn't already contain a header with the same name.
|
||||||
|
*
|
||||||
|
* @group response
|
||||||
*/
|
*/
|
||||||
def respondWithDefaultHeader(responseHeader: HttpHeader): Directive0 = respondWithDefaultHeaders(responseHeader)
|
def respondWithDefaultHeader(responseHeader: HttpHeader): Directive0 = respondWithDefaultHeaders(responseHeader)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unconditionally adds the given response headers to all HTTP responses of its inner Route.
|
* Unconditionally adds the given response headers to all HTTP responses of its inner Route.
|
||||||
|
*
|
||||||
|
* @group response
|
||||||
*/
|
*/
|
||||||
def respondWithHeaders(responseHeaders: HttpHeader*): Directive0 =
|
def respondWithHeaders(responseHeaders: HttpHeader*): Directive0 =
|
||||||
respondWithHeaders(responseHeaders.toList)
|
respondWithHeaders(responseHeaders.toList)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unconditionally adds the given response headers to all HTTP responses of its inner Route.
|
* Unconditionally adds the given response headers to all HTTP responses of its inner Route.
|
||||||
|
*
|
||||||
|
* @group response
|
||||||
*/
|
*/
|
||||||
def respondWithHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 =
|
def respondWithHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 =
|
||||||
mapResponseHeaders(responseHeaders ++ _)
|
mapResponseHeaders(responseHeaders ++ _)
|
||||||
|
|
@ -33,12 +45,17 @@ trait RespondWithDirectives {
|
||||||
/**
|
/**
|
||||||
* Adds the given response headers to all HTTP responses of its inner Route,
|
* Adds the given response headers to all HTTP responses of its inner Route,
|
||||||
* if a header already exists it is not added again.
|
* if a header already exists it is not added again.
|
||||||
|
*
|
||||||
|
* @group response
|
||||||
*/
|
*/
|
||||||
def respondWithDefaultHeaders(responseHeaders: HttpHeader*): Directive0 =
|
def respondWithDefaultHeaders(responseHeaders: HttpHeader*): Directive0 =
|
||||||
respondWithDefaultHeaders(responseHeaders.toList)
|
respondWithDefaultHeaders(responseHeaders.toList)
|
||||||
|
|
||||||
/* Adds the given response headers to all HTTP responses of its inner Route,
|
/**
|
||||||
|
* Adds the given response headers to all HTTP responses of its inner Route,
|
||||||
* if a header already exists it is not added again.
|
* if a header already exists it is not added again.
|
||||||
|
*
|
||||||
|
* @group response
|
||||||
*/
|
*/
|
||||||
def respondWithDefaultHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 =
|
def respondWithDefaultHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 =
|
||||||
mapResponse(_.withDefaultHeaders(responseHeaders))
|
mapResponse(_.withDefaultHeaders(responseHeaders))
|
||||||
|
|
|
||||||
|
|
@ -9,21 +9,31 @@ import akka.http.scaladsl.marshalling.ToResponseMarshallable
|
||||||
import akka.http.scaladsl.model._
|
import akka.http.scaladsl.model._
|
||||||
import StatusCodes._
|
import StatusCodes._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname route Route directives
|
||||||
|
* @groupprio route 200
|
||||||
|
*/
|
||||||
trait RouteDirectives {
|
trait RouteDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects the request with an empty set of rejections.
|
* Rejects the request with an empty set of rejections.
|
||||||
|
*
|
||||||
|
* @group route
|
||||||
*/
|
*/
|
||||||
def reject: StandardRoute = RouteDirectives._reject
|
def reject: StandardRoute = RouteDirectives._reject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects the request with the given rejections.
|
* Rejects the request with the given rejections.
|
||||||
|
*
|
||||||
|
* @group route
|
||||||
*/
|
*/
|
||||||
def reject(rejections: Rejection*): StandardRoute =
|
def reject(rejections: Rejection*): StandardRoute =
|
||||||
StandardRoute(_.reject(rejections: _*))
|
StandardRoute(_.reject(rejections: _*))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completes the request with redirection response of the given type to the given URI.
|
* Completes the request with redirection response of the given type to the given URI.
|
||||||
|
*
|
||||||
|
* @group route
|
||||||
*/
|
*/
|
||||||
def redirect(uri: Uri, redirectionType: Redirection): StandardRoute =
|
def redirect(uri: Uri, redirectionType: Redirection): StandardRoute =
|
||||||
StandardRoute {
|
StandardRoute {
|
||||||
|
|
@ -42,6 +52,8 @@ trait RouteDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completes the request using the given arguments.
|
* Completes the request using the given arguments.
|
||||||
|
*
|
||||||
|
* @group route
|
||||||
*/
|
*/
|
||||||
def complete(m: ⇒ ToResponseMarshallable): StandardRoute =
|
def complete(m: ⇒ ToResponseMarshallable): StandardRoute =
|
||||||
StandardRoute(_.complete(m))
|
StandardRoute(_.complete(m))
|
||||||
|
|
@ -49,6 +61,8 @@ trait RouteDirectives {
|
||||||
/**
|
/**
|
||||||
* Bubbles the given error up the response chain, where it is dealt with by the closest `handleExceptions`
|
* Bubbles the given error up the response chain, where it is dealt with by the closest `handleExceptions`
|
||||||
* directive and its ExceptionHandler.
|
* directive and its ExceptionHandler.
|
||||||
|
*
|
||||||
|
* @group route
|
||||||
*/
|
*/
|
||||||
def failWith(error: Throwable): StandardRoute =
|
def failWith(error: Throwable): StandardRoute =
|
||||||
StandardRoute(_.fail(error))
|
StandardRoute(_.fail(error))
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,24 @@
|
||||||
package akka.http.scaladsl.server
|
package akka.http.scaladsl.server
|
||||||
package directives
|
package directives
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname scheme Scheme directives
|
||||||
|
* @groupprio scheme 210
|
||||||
|
*/
|
||||||
trait SchemeDirectives {
|
trait SchemeDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the Uri scheme from the request.
|
* Extracts the Uri scheme from the request.
|
||||||
|
*
|
||||||
|
* @group scheme
|
||||||
*/
|
*/
|
||||||
def extractScheme: Directive1[String] = SchemeDirectives._extractScheme
|
def extractScheme: Directive1[String] = SchemeDirectives._extractScheme
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects all requests whose Uri scheme does not match the given one.
|
* Rejects all requests whose Uri scheme does not match the given one.
|
||||||
|
*
|
||||||
|
* @group scheme
|
||||||
*/
|
*/
|
||||||
def scheme(name: String): Directive0 =
|
def scheme(name: String): Directive0 =
|
||||||
extractScheme.require(_ == name, SchemeRejection(name)) & cancelRejections(classOf[SchemeRejection])
|
extractScheme.require(_ == name, SchemeRejection(name)) & cancelRejections(classOf[SchemeRejection])
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ import scala.util.{Try, Success}
|
||||||
* and [[Authorization]]. Most prominently, HTTP Basic authentication as defined in RFC 2617.
|
* and [[Authorization]]. Most prominently, HTTP Basic authentication as defined in RFC 2617.
|
||||||
*
|
*
|
||||||
* See: <a href="https://www.ietf.org/rfc/rfc2617.txt">RFC 2617</a>.
|
* See: <a href="https://www.ietf.org/rfc/rfc2617.txt">RFC 2617</a>.
|
||||||
|
*
|
||||||
|
* @groupname security Security directives
|
||||||
|
* @groupprio security 220
|
||||||
*/
|
*/
|
||||||
trait SecurityDirectives {
|
trait SecurityDirectives {
|
||||||
import BasicDirectives._
|
import BasicDirectives._
|
||||||
|
|
@ -31,25 +34,41 @@ trait SecurityDirectives {
|
||||||
/**
|
/**
|
||||||
* The result of an HTTP authentication attempt is either the user object or
|
* The result of an HTTP authentication attempt is either the user object or
|
||||||
* an HttpChallenge to present to the browser.
|
* an HttpChallenge to present to the browser.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
type AuthenticationResult[+T] = Either[HttpChallenge, T]
|
type AuthenticationResult[+T] = Either[HttpChallenge, T]
|
||||||
//#authentication-result
|
//#authentication-result
|
||||||
|
|
||||||
//#authenticator
|
//#authenticator
|
||||||
|
/**
|
||||||
|
* @group security
|
||||||
|
*/
|
||||||
type Authenticator[T] = Credentials ⇒ Option[T]
|
type Authenticator[T] = Credentials ⇒ Option[T]
|
||||||
//#authenticator
|
//#authenticator
|
||||||
//#async-authenticator
|
//#async-authenticator
|
||||||
|
/**
|
||||||
|
* @group security
|
||||||
|
*/
|
||||||
type AsyncAuthenticator[T] = Credentials ⇒ Future[Option[T]]
|
type AsyncAuthenticator[T] = Credentials ⇒ Future[Option[T]]
|
||||||
//#async-authenticator
|
//#async-authenticator
|
||||||
//#authenticator-pf
|
//#authenticator-pf
|
||||||
|
/**
|
||||||
|
* @group security
|
||||||
|
*/
|
||||||
type AuthenticatorPF[T] = PartialFunction[Credentials, T]
|
type AuthenticatorPF[T] = PartialFunction[Credentials, T]
|
||||||
//#authenticator-pf
|
//#authenticator-pf
|
||||||
//#async-authenticator-pf
|
//#async-authenticator-pf
|
||||||
|
/**
|
||||||
|
* @group security
|
||||||
|
*/
|
||||||
type AsyncAuthenticatorPF[T] = PartialFunction[Credentials, Future[T]]
|
type AsyncAuthenticatorPF[T] = PartialFunction[Credentials, Future[T]]
|
||||||
//#async-authenticator-pf
|
//#async-authenticator-pf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the potentially present [[HttpCredentials]] provided with the request's [[Authorization]] header.
|
* Extracts the potentially present [[HttpCredentials]] provided with the request's [[Authorization]] header.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def extractCredentials: Directive1[Option[HttpCredentials]] =
|
def extractCredentials: Directive1[Option[HttpCredentials]] =
|
||||||
optionalHeaderValueByType[Authorization](()).map(_.map(_.credentials))
|
optionalHeaderValueByType[Authorization](()).map(_.map(_.credentials))
|
||||||
|
|
@ -58,6 +77,8 @@ trait SecurityDirectives {
|
||||||
* Wraps the inner route with Http Basic authentication support using a given `Authenticator[T]`.
|
* Wraps the inner route with Http Basic authentication support using a given `Authenticator[T]`.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateBasic[T](realm: String, authenticator: Authenticator[T]): AuthenticationDirective[T] =
|
def authenticateBasic[T](realm: String, authenticator: Authenticator[T]): AuthenticationDirective[T] =
|
||||||
authenticateBasicAsync(realm, cred ⇒ FastFuture.successful(authenticator(cred)))
|
authenticateBasicAsync(realm, cred ⇒ FastFuture.successful(authenticator(cred)))
|
||||||
|
|
@ -66,6 +87,8 @@ trait SecurityDirectives {
|
||||||
* Wraps the inner route with Http Basic authentication support.
|
* Wraps the inner route with Http Basic authentication support.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateBasicAsync[T](realm: String, authenticator: AsyncAuthenticator[T]): AuthenticationDirective[T] =
|
def authenticateBasicAsync[T](realm: String, authenticator: AsyncAuthenticator[T]): AuthenticationDirective[T] =
|
||||||
extractExecutionContext.flatMap { implicit ec ⇒
|
extractExecutionContext.flatMap { implicit ec ⇒
|
||||||
|
|
@ -81,6 +104,8 @@ trait SecurityDirectives {
|
||||||
* A directive that wraps the inner route with Http Basic authentication support.
|
* A directive that wraps the inner route with Http Basic authentication support.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateBasicPF[T](realm: String, authenticator: AuthenticatorPF[T]): AuthenticationDirective[T] =
|
def authenticateBasicPF[T](realm: String, authenticator: AuthenticatorPF[T]): AuthenticationDirective[T] =
|
||||||
authenticateBasic(realm, authenticator.lift)
|
authenticateBasic(realm, authenticator.lift)
|
||||||
|
|
@ -89,6 +114,8 @@ trait SecurityDirectives {
|
||||||
* A directive that wraps the inner route with Http Basic authentication support.
|
* A directive that wraps the inner route with Http Basic authentication support.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateBasicPFAsync[T](realm: String, authenticator: AsyncAuthenticatorPF[T]): AuthenticationDirective[T] =
|
def authenticateBasicPFAsync[T](realm: String, authenticator: AsyncAuthenticatorPF[T]): AuthenticationDirective[T] =
|
||||||
extractExecutionContext.flatMap { implicit ec ⇒
|
extractExecutionContext.flatMap { implicit ec ⇒
|
||||||
|
|
@ -101,6 +128,8 @@ trait SecurityDirectives {
|
||||||
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateOAuth2[T](realm: String, authenticator: Authenticator[T]): AuthenticationDirective[T] =
|
def authenticateOAuth2[T](realm: String, authenticator: Authenticator[T]): AuthenticationDirective[T] =
|
||||||
authenticateOAuth2Async(realm, cred ⇒ FastFuture.successful(authenticator(cred)))
|
authenticateOAuth2Async(realm, cred ⇒ FastFuture.successful(authenticator(cred)))
|
||||||
|
|
@ -109,6 +138,8 @@ trait SecurityDirectives {
|
||||||
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateOAuth2Async[T](realm: String, authenticator: AsyncAuthenticator[T]): AuthenticationDirective[T] =
|
def authenticateOAuth2Async[T](realm: String, authenticator: AsyncAuthenticator[T]): AuthenticationDirective[T] =
|
||||||
extractExecutionContext.flatMap { implicit ec ⇒
|
extractExecutionContext.flatMap { implicit ec ⇒
|
||||||
|
|
@ -124,6 +155,8 @@ trait SecurityDirectives {
|
||||||
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateOAuth2PF[T](realm: String, authenticator: AuthenticatorPF[T]): AuthenticationDirective[T] =
|
def authenticateOAuth2PF[T](realm: String, authenticator: AuthenticatorPF[T]): AuthenticationDirective[T] =
|
||||||
authenticateOAuth2(realm, authenticator.lift)
|
authenticateOAuth2(realm, authenticator.lift)
|
||||||
|
|
@ -132,6 +165,8 @@ trait SecurityDirectives {
|
||||||
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
* A directive that wraps the inner route with OAuth2 Bearer Token authentication support.
|
||||||
* The given authenticator determines whether the credentials in the request are valid
|
* The given authenticator determines whether the credentials in the request are valid
|
||||||
* and, if so, which user object to supply to the inner route.
|
* and, if so, which user object to supply to the inner route.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateOAuth2PFAsync[T](realm: String, authenticator: AsyncAuthenticatorPF[T]): AuthenticationDirective[T] =
|
def authenticateOAuth2PFAsync[T](realm: String, authenticator: AsyncAuthenticatorPF[T]): AuthenticationDirective[T] =
|
||||||
extractExecutionContext.flatMap { implicit ec ⇒
|
extractExecutionContext.flatMap { implicit ec ⇒
|
||||||
|
|
@ -146,6 +181,7 @@ trait SecurityDirectives {
|
||||||
* to the inner route. If the function returns `Left(challenge)` the request is rejected with an
|
* to the inner route. If the function returns `Left(challenge)` the request is rejected with an
|
||||||
* [[AuthenticationFailedRejection]] that contains this challenge to be added to the response.
|
* [[AuthenticationFailedRejection]] that contains this challenge to be added to the response.
|
||||||
*
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateOrRejectWithChallenge[T](authenticator: Option[HttpCredentials] ⇒ Future[AuthenticationResult[T]]): AuthenticationDirective[T] =
|
def authenticateOrRejectWithChallenge[T](authenticator: Option[HttpCredentials] ⇒ Future[AuthenticationResult[T]]): AuthenticationDirective[T] =
|
||||||
extractExecutionContext.flatMap { implicit ec ⇒
|
extractExecutionContext.flatMap { implicit ec ⇒
|
||||||
|
|
@ -162,6 +198,8 @@ trait SecurityDirectives {
|
||||||
/**
|
/**
|
||||||
* Lifts an authenticator function into a directive. Same as `authenticateOrRejectWithChallenge`
|
* Lifts an authenticator function into a directive. Same as `authenticateOrRejectWithChallenge`
|
||||||
* but only applies the authenticator function with a certain type of credentials.
|
* but only applies the authenticator function with a certain type of credentials.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authenticateOrRejectWithChallenge[C <: HttpCredentials: ClassTag, T](
|
def authenticateOrRejectWithChallenge[C <: HttpCredentials: ClassTag, T](
|
||||||
authenticator: Option[C] ⇒ Future[AuthenticationResult[T]]): AuthenticationDirective[T] =
|
authenticator: Option[C] ⇒ Future[AuthenticationResult[T]]): AuthenticationDirective[T] =
|
||||||
|
|
@ -170,12 +208,16 @@ trait SecurityDirectives {
|
||||||
/**
|
/**
|
||||||
* Applies the given authorization check to the request.
|
* Applies the given authorization check to the request.
|
||||||
* If the check fails the route is rejected with an [[AuthorizationFailedRejection]].
|
* If the check fails the route is rejected with an [[AuthorizationFailedRejection]].
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authorize(check: ⇒ Boolean): Directive0 = authorize(_ ⇒ check)
|
def authorize(check: ⇒ Boolean): Directive0 = authorize(_ ⇒ check)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the given authorization check to the request.
|
* Applies the given authorization check to the request.
|
||||||
* If the check fails the route is rejected with an [[AuthorizationFailedRejection]].
|
* If the check fails the route is rejected with an [[AuthorizationFailedRejection]].
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authorize(check: RequestContext ⇒ Boolean): Directive0 =
|
def authorize(check: RequestContext ⇒ Boolean): Directive0 =
|
||||||
authorizeAsync(ctx => Future.successful(check(ctx)))
|
authorizeAsync(ctx => Future.successful(check(ctx)))
|
||||||
|
|
@ -184,6 +226,8 @@ trait SecurityDirectives {
|
||||||
* Asynchronous version of [[authorize]].
|
* Asynchronous version of [[authorize]].
|
||||||
* If the [[Future]] fails or is completed with `false`
|
* If the [[Future]] fails or is completed with `false`
|
||||||
* authorization fails and the route is rejected with an [[AuthorizationFailedRejection]].
|
* authorization fails and the route is rejected with an [[AuthorizationFailedRejection]].
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authorizeAsync(check: ⇒ Future[Boolean]): Directive0 =
|
def authorizeAsync(check: ⇒ Future[Boolean]): Directive0 =
|
||||||
authorizeAsync(ctx => check)
|
authorizeAsync(ctx => check)
|
||||||
|
|
@ -192,6 +236,8 @@ trait SecurityDirectives {
|
||||||
* Asynchronous version of [[authorize]].
|
* Asynchronous version of [[authorize]].
|
||||||
* If the [[Future]] fails or is completed with `false`
|
* If the [[Future]] fails or is completed with `false`
|
||||||
* authorization fails and the route is rejected with an [[AuthorizationFailedRejection]].
|
* authorization fails and the route is rejected with an [[AuthorizationFailedRejection]].
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def authorizeAsync(check: RequestContext ⇒ Future[Boolean]): Directive0 =
|
def authorizeAsync(check: RequestContext ⇒ Future[Boolean]): Directive0 =
|
||||||
extractExecutionContext.flatMap { implicit ec ⇒
|
extractExecutionContext.flatMap { implicit ec ⇒
|
||||||
|
|
@ -205,6 +251,8 @@ trait SecurityDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a `Basic` [[HttpChallenge]] for the given realm.
|
* Creates a `Basic` [[HttpChallenge]] for the given realm.
|
||||||
|
*
|
||||||
|
* @group security
|
||||||
*/
|
*/
|
||||||
def challengeFor(realm: String) = HttpChallenge(scheme = "Basic", realm = realm, params = Map.empty)
|
def challengeFor(realm: String) = HttpChallenge(scheme = "Basic", realm = realm, params = Map.empty)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,15 @@ import akka.http.scaladsl.server.{ Directive, Directive0 }
|
||||||
|
|
||||||
import scala.concurrent.duration.Duration
|
import scala.concurrent.duration.Duration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname timeout Timeout directives
|
||||||
|
* @groupprio timeout 160
|
||||||
|
*/
|
||||||
trait TimeoutDirectives {
|
trait TimeoutDirectives {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group timeout
|
||||||
|
*/
|
||||||
def withoutRequestTimeout: Directive0 =
|
def withoutRequestTimeout: Directive0 =
|
||||||
withRequestTimeout(Duration.Inf)
|
withRequestTimeout(Duration.Inf)
|
||||||
|
|
||||||
|
|
@ -20,6 +27,8 @@ trait TimeoutDirectives {
|
||||||
*
|
*
|
||||||
* Due to the inherent raciness it is not guaranteed that the update will be applied before
|
* Due to the inherent raciness it is not guaranteed that the update will be applied before
|
||||||
* the previously set timeout has expired!
|
* the previously set timeout has expired!
|
||||||
|
*
|
||||||
|
* @group timeout
|
||||||
*/
|
*/
|
||||||
def withRequestTimeout(timeout: Duration): Directive0 =
|
def withRequestTimeout(timeout: Duration): Directive0 =
|
||||||
withRequestTimeout(timeout, None)
|
withRequestTimeout(timeout, None)
|
||||||
|
|
@ -31,6 +40,8 @@ trait TimeoutDirectives {
|
||||||
* the previously set timeout has expired!
|
* the previously set timeout has expired!
|
||||||
*
|
*
|
||||||
* @param handler optional custom "timeout response" function. If left None, the default timeout HttpResponse will be used.
|
* @param handler optional custom "timeout response" function. If left None, the default timeout HttpResponse will be used.
|
||||||
|
*
|
||||||
|
* @group timeout
|
||||||
*/
|
*/
|
||||||
def withRequestTimeout(timeout: Duration, handler: HttpRequest ⇒ HttpResponse): Directive0 =
|
def withRequestTimeout(timeout: Duration, handler: HttpRequest ⇒ HttpResponse): Directive0 =
|
||||||
withRequestTimeout(timeout, Some(handler))
|
withRequestTimeout(timeout, Some(handler))
|
||||||
|
|
@ -42,6 +53,8 @@ trait TimeoutDirectives {
|
||||||
* the previously set timeout has expired!
|
* the previously set timeout has expired!
|
||||||
*
|
*
|
||||||
* @param handler optional custom "timeout response" function. If left None, the default timeout HttpResponse will be used.
|
* @param handler optional custom "timeout response" function. If left None, the default timeout HttpResponse will be used.
|
||||||
|
*
|
||||||
|
* @group timeout
|
||||||
*/
|
*/
|
||||||
def withRequestTimeout(timeout: Duration, handler: Option[HttpRequest ⇒ HttpResponse]): Directive0 =
|
def withRequestTimeout(timeout: Duration, handler: Option[HttpRequest ⇒ HttpResponse]): Directive0 =
|
||||||
Directive { inner ⇒
|
Directive { inner ⇒
|
||||||
|
|
@ -63,6 +76,8 @@ trait TimeoutDirectives {
|
||||||
*
|
*
|
||||||
* Due to the inherent raciness it is not guaranteed that the update will be applied before
|
* Due to the inherent raciness it is not guaranteed that the update will be applied before
|
||||||
* the previously set timeout has expired!
|
* the previously set timeout has expired!
|
||||||
|
*
|
||||||
|
* @group timeout
|
||||||
*/
|
*/
|
||||||
def withRequestTimeoutResponse(handler: HttpRequest ⇒ HttpResponse): Directive0 =
|
def withRequestTimeoutResponse(handler: HttpRequest ⇒ HttpResponse): Directive0 =
|
||||||
Directive { inner ⇒
|
Directive { inner ⇒
|
||||||
|
|
@ -76,4 +91,4 @@ trait TimeoutDirectives {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object TimeoutDirectives extends TimeoutDirectives
|
object TimeoutDirectives extends TimeoutDirectives
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@ import scala.collection.immutable
|
||||||
import akka.http.scaladsl.model.ws.{ UpgradeToWebSocket, Message }
|
import akka.http.scaladsl.model.ws.{ UpgradeToWebSocket, Message }
|
||||||
import akka.stream.scaladsl.Flow
|
import akka.stream.scaladsl.Flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @groupname websocket WebSocket directives
|
||||||
|
* @groupprio websocket 230
|
||||||
|
*/
|
||||||
trait WebSocketDirectives {
|
trait WebSocketDirectives {
|
||||||
import RouteDirectives._
|
import RouteDirectives._
|
||||||
import HeaderDirectives._
|
import HeaderDirectives._
|
||||||
|
|
@ -17,6 +21,8 @@ trait WebSocketDirectives {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the [[UpgradeToWebSocket]] header if existent. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise.
|
* Extract the [[UpgradeToWebSocket]] header if existent. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise.
|
||||||
|
*
|
||||||
|
* @group websocket
|
||||||
*/
|
*/
|
||||||
def extractUpgradeToWebSocket: Directive1[UpgradeToWebSocket] =
|
def extractUpgradeToWebSocket: Directive1[UpgradeToWebSocket] =
|
||||||
optionalHeaderValueByType[UpgradeToWebSocket](()).flatMap {
|
optionalHeaderValueByType[UpgradeToWebSocket](()).flatMap {
|
||||||
|
|
@ -27,12 +33,16 @@ trait WebSocketDirectives {
|
||||||
/**
|
/**
|
||||||
* Extract the list of WebSocket subprotocols as offered by the client in the [[Sec-WebSocket-Protocol]] header if
|
* Extract the list of WebSocket subprotocols as offered by the client in the [[Sec-WebSocket-Protocol]] header if
|
||||||
* this is a WebSocket request. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise.
|
* this is a WebSocket request. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise.
|
||||||
|
*
|
||||||
|
* @group websocket
|
||||||
*/
|
*/
|
||||||
def extractOfferedWsProtocols: Directive1[immutable.Seq[String]] = extractUpgradeToWebSocket.map(_.requestedProtocols)
|
def extractOfferedWsProtocols: Directive1[immutable.Seq[String]] = extractUpgradeToWebSocket.map(_.requestedProtocols)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles WebSocket requests with the given handler and rejects other requests with an
|
* Handles WebSocket requests with the given handler and rejects other requests with an
|
||||||
* [[ExpectedWebSocketRequestRejection]].
|
* [[ExpectedWebSocketRequestRejection]].
|
||||||
|
*
|
||||||
|
* @group websocket
|
||||||
*/
|
*/
|
||||||
def handleWebSocketMessages(handler: Flow[Message, Message, Any]): Route =
|
def handleWebSocketMessages(handler: Flow[Message, Message, Any]): Route =
|
||||||
handleWebSocketMessagesForOptionalProtocol(handler, None)
|
handleWebSocketMessagesForOptionalProtocol(handler, None)
|
||||||
|
|
@ -40,6 +50,8 @@ trait WebSocketDirectives {
|
||||||
/**
|
/**
|
||||||
* Handles WebSocket requests with the given handler if the given subprotocol is offered in the request and
|
* Handles WebSocket requests with the given handler if the given subprotocol is offered in the request and
|
||||||
* rejects other requests with an [[ExpectedWebSocketRequestRejection]] or an [[UnsupportedWebSocketSubprotocolRejection]].
|
* rejects other requests with an [[ExpectedWebSocketRequestRejection]] or an [[UnsupportedWebSocketSubprotocolRejection]].
|
||||||
|
*
|
||||||
|
* @group websocket
|
||||||
*/
|
*/
|
||||||
def handleWebSocketMessagesForProtocol(handler: Flow[Message, Message, Any], subprotocol: String): Route =
|
def handleWebSocketMessagesForProtocol(handler: Flow[Message, Message, Any], subprotocol: String): Route =
|
||||||
handleWebSocketMessagesForOptionalProtocol(handler, Some(subprotocol))
|
handleWebSocketMessagesForOptionalProtocol(handler, Some(subprotocol))
|
||||||
|
|
@ -54,6 +66,8 @@ trait WebSocketDirectives {
|
||||||
* the request is rejected with an [[UnsupportedWebSocketSubprotocolRejection]] rejection.
|
* the request is rejected with an [[UnsupportedWebSocketSubprotocolRejection]] rejection.
|
||||||
*
|
*
|
||||||
* To support several subprotocols you may chain several `handleWebSocketMessage` Routes.
|
* To support several subprotocols you may chain several `handleWebSocketMessage` Routes.
|
||||||
|
*
|
||||||
|
* @group websocket
|
||||||
*/
|
*/
|
||||||
def handleWebSocketMessagesForOptionalProtocol(handler: Flow[Message, Message, Any], subprotocol: Option[String]): Route =
|
def handleWebSocketMessagesForOptionalProtocol(handler: Flow[Message, Message, Any], subprotocol: Option[String]): Route =
|
||||||
extractUpgradeToWebSocket { upgrade ⇒
|
extractUpgradeToWebSocket { upgrade ⇒
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ object Scaladoc extends AutoPlugin {
|
||||||
|
|
||||||
def scaladocOptions(ver: String, base: File): List[String] = {
|
def scaladocOptions(ver: String, base: File): List[String] = {
|
||||||
val urlString = GitHub.url(ver) + "/€{FILE_PATH}.scala"
|
val urlString = GitHub.url(ver) + "/€{FILE_PATH}.scala"
|
||||||
val opts = List("-implicits", "-doc-source-url", urlString, "-sourcepath", base.getAbsolutePath)
|
val opts = List("-implicits", "-groups", "-doc-source-url", urlString, "-sourcepath", base.getAbsolutePath)
|
||||||
CliOptions.scaladocDiagramsEnabled.ifTrue("-diagrams").toList ::: opts
|
CliOptions.scaladocDiagramsEnabled.ifTrue("-diagrams").toList ::: opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue