From aec81c2ac2526638d63db3ead642cb68f2f3d928 Mon Sep 17 00:00:00 2001 From: Lars Hupel Date: Mon, 4 Apr 2016 11:50:44 +0200 Subject: [PATCH] htp #20103 introduce Scaladoc groups for Directives --- .../http/scaladsl/common/NameReceptacle.scala | 2 +- .../http/scaladsl/server/PathMatcher.scala | 56 +++++++++++ .../scaladsl/server/RouteConcatenation.scala | 9 +- .../server/directives/BasicDirectives.scala | 92 +++++++++++++++++++ .../directives/CacheConditionDirectives.scala | 12 +++ .../server/directives/CodingDirectives.scala | 20 ++++ .../server/directives/CookieDirectives.scala | 14 +++ .../directives/DebuggingDirectives.scala | 10 ++ .../directives/ExecutionDirectives.scala | 10 +- .../FileAndResourceDirectives.scala | 24 +++++ .../directives/FileUploadDirectives.scala | 8 ++ .../directives/FormFieldDirectives.scala | 14 +++ .../server/directives/FutureDirectives.scala | 10 ++ .../server/directives/HeaderDirectives.scala | 26 +++++- .../server/directives/HostDirectives.scala | 12 +++ .../directives/MarshallingDirectives.scala | 14 +++ .../server/directives/MethodDirectives.scala | 24 +++++ .../server/directives/MiscDirectives.scala | 16 ++++ .../directives/ParameterDirectives.scala | 16 +++- .../server/directives/PathDirectives.scala | 28 ++++++ .../server/directives/RangeDirectives.scala | 6 ++ .../directives/RespondWithDirectives.scala | 19 +++- .../server/directives/RouteDirectives.scala | 14 +++ .../server/directives/SchemeDirectives.scala | 8 ++ .../directives/SecurityDirectives.scala | 48 ++++++++++ .../server/directives/TimeoutDirectives.scala | 17 +++- .../directives/WebSocketDirectives.scala | 14 +++ project/Doc.scala | 2 +- 28 files changed, 537 insertions(+), 8 deletions(-) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala b/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala index a3f8531a6b..5e5cc8ec7c 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala @@ -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 RepeatedValueUnmarshallerReceptacle[T](val name: String, val um: FSU[T]) \ No newline at end of file +class RepeatedValueUnmarshallerReceptacle[T](val name: String, val um: FSU[T]) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/PathMatcher.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/PathMatcher.scala index 1c72aed1d7..51c3ee97de 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/PathMatcher.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/PathMatcher.scala @@ -223,12 +223,18 @@ object PathMatcher extends ImplicitPathMatcherConstruction { } } +/** + * @groupname pathmatcherimpl Path matcher implicits + * @groupprio pathmatcherimpl 172 + */ trait ImplicitPathMatcherConstruction { import PathMatcher._ /** * Creates a PathMatcher that consumes (a prefix of) the first path segment * (if the path begins with a segment) and extracts a given value. + * + * @group pathmatcherimpl */ implicit def stringExtractionPair2PathMatcher[T](tuple: (String, T)): PathMatcher1[T] = 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 * (if the path begins with a segment). + * + * @group pathmatcherimpl */ implicit def segmentStringToPathMatcher(segment: String): PathMatcher0 = PathMatcher(segment :: Path.Empty, ()) + /** + * @group pathmatcherimpl + */ implicit def stringNameOptionReceptacle2PathMatcher(nr: NameOptionReceptacle[String]): PathMatcher0 = PathMatcher(nr.name).? @@ -249,6 +260,8 @@ trait ImplicitPathMatcherConstruction { * Extracts either the complete match (if the regex doesn't contain a capture group) or * the capture group (if the regex contains exactly one). * 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 { 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. * 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. + * + * @group pathmatcherimpl */ implicit def valueMap2PathMatcher[T](valueMap: Map[String, T]): PathMatcher1[T] = if (valueMap.isEmpty) PathMatchers.nothingMatcher else valueMap.map { case (prefix, value) ⇒ stringExtractionPair2PathMatcher((prefix, value)) }.reduceLeft(_ | _) } +/** + * @groupname pathmatcher Path matchers + * @groupprio pathmatcher 171 + */ trait PathMatchers { import PathMatcher._ /** * Converts a path string containing slashes into a PathMatcher that interprets slashes as * path segment separators. + * + * @group pathmatcher */ def separateOnSlashes(string: String): 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 ('/'). + * + * @group pathmatcher */ object Slash extends PathMatcher0 { def apply(path: Path) = path match { @@ -311,6 +334,8 @@ trait PathMatchers { /** * A PathMatcher that matches the very end of the requests URI path. + * + * @group pathmatcher */ object PathEnd extends PathMatcher0 { def apply(path: Path) = path match { @@ -324,6 +349,8 @@ trait PathMatchers { * unmatched part of the request's URI path as an (encoded!) String. * If you need access to the remaining unencoded elements of the path * use the `RestPath` matcher! + * + * @group pathmatcher */ object Rest extends PathMatcher1[String] { 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, * unmatched part of the request's URI path. + * + * @group pathmatcher */ object RestPath extends PathMatcher1[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. * The matcher will not match 0 digits or a sequence of digits that would represent an Int value larger * than Int.MaxValue. + * + * @group pathmatcher */ object IntNumber extends NumberMatcher[Int](Int.MaxValue, 10) { 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. * The matcher will not match 0 digits or a sequence of digits that would represent an Long value larger * than Long.MaxValue. + * + * @group pathmatcher */ object LongNumber extends NumberMatcher[Long](Long.MaxValue, 10) { 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. * The matcher will not match 0 digits or a sequence of digits that would represent an Int value larger * than Int.MaxValue. + * + * @group pathmatcher */ object HexIntNumber extends NumberMatcher[Int](Int.MaxValue, 16) { 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. * The matcher will not match 0 digits or a sequence of digits that would represent an Long value larger * than Long.MaxValue. + * + * @group pathmatcher */ object HexLongNumber extends NumberMatcher[Long](Long.MaxValue, 16) { def fromChar(c: Char) = fromHexChar(c) } // common implementation of Number matchers + /** + * @group pathmatcher + */ abstract class NumberMatcher[@specialized(Int, Long) T](max: T, base: T)(implicit x: Integral[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, * optionally signed form of a double value, i.e. without exponent. + * + * @group pathmatcher */ val DoubleNumber: PathMatcher1[Double] = PathMatcher("""[+-]?\d*\.?\d*""".r) flatMap { string ⇒ @@ -423,6 +465,8 @@ trait PathMatchers { /** * A PathMatcher that matches and extracts a java.util.UUID instance. + * + * @group pathmatcher */ 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 ⇒ @@ -433,12 +477,16 @@ trait PathMatchers { /** * A PathMatcher that always matches, doesn't consume anything and extracts nothing. * Serves mainly as a neutral element in PathMatcher composition. + * + * @group pathmatcher */ val Neutral: PathMatcher0 = PathMatcher.provide(()) /** * A PathMatcher that matches if the unmatched path starts with a path segment. * If so the path segment is extracted as a String. + * + * @group pathmatcher */ object Segment extends PathMatcher1[String] { 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]. * This can also be no segments resulting in the empty list. * 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) @@ -458,6 +508,8 @@ trait PathMatchers { * 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 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) @@ -465,11 +517,15 @@ trait PathMatchers { * 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. * 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) /** * A PathMatcher that never matches anything. + * + * @group pathmatcher */ def nothingMatcher[L: Tuple]: PathMatcher[L] = new PathMatcher[L] { diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/RouteConcatenation.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/RouteConcatenation.scala index 117dec5b2e..80b0b83385 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/RouteConcatenation.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/RouteConcatenation.scala @@ -7,8 +7,15 @@ package akka.http.scaladsl.server import akka.http.scaladsl.util.FastFuture import akka.http.scaladsl.util.FastFuture._ +/** + * @groupname concat Route concatenation + * @groupprio concat 300 + */ trait RouteConcatenation { + /** + * @group concat + */ implicit def enhanceRouteWithConcatenation(route: Route): RouteConcatenation.RouteWithConcatenation = new RouteConcatenation.RouteWithConcatenation(route: Route) } @@ -32,4 +39,4 @@ object RouteConcatenation extends RouteConcatenation { } } } -} \ No newline at end of file +} diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala index 3f85638f87..93d4952163 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala @@ -15,75 +15,131 @@ import akka.http.scaladsl.util.FastFuture import akka.http.scaladsl.model._ import akka.http.scaladsl.util.FastFuture._ +/** + * @groupname basic Basic directives + * @groupprio basic 10 + */ trait BasicDirectives { + /** + * @group basic + */ def mapInnerRoute(f: Route ⇒ Route): Directive0 = Directive { inner ⇒ f(inner(())) } + /** + * @group basic + */ def mapRequestContext(f: RequestContext ⇒ RequestContext): Directive0 = mapInnerRoute { inner ⇒ ctx ⇒ inner(f(ctx)) } + /** + * @group basic + */ def mapRequest(f: HttpRequest ⇒ HttpRequest): Directive0 = mapRequestContext(_ mapRequest f) + /** + * @group basic + */ def mapRouteResultFuture(f: Future[RouteResult] ⇒ Future[RouteResult]): Directive0 = Directive { inner ⇒ ctx ⇒ f(inner(())(ctx)) } + /** + * @group basic + */ def mapRouteResult(f: RouteResult ⇒ RouteResult): Directive0 = Directive { inner ⇒ ctx ⇒ inner(())(ctx).fast.map(f)(ctx.executionContext) } + /** + * @group basic + */ def mapRouteResultWith(f: RouteResult ⇒ Future[RouteResult]): Directive0 = Directive { inner ⇒ ctx ⇒ inner(())(ctx).fast.flatMap(f)(ctx.executionContext) } + /** + * @group basic + */ def mapRouteResultPF(f: PartialFunction[RouteResult, RouteResult]): Directive0 = mapRouteResult(f.applyOrElse(_, conforms[RouteResult])) + /** + * @group basic + */ def mapRouteResultWithPF(f: PartialFunction[RouteResult, Future[RouteResult]]): Directive0 = mapRouteResultWith(f.applyOrElse(_, FastFuture.successful[RouteResult])) + /** + * @group basic + */ def recoverRejections(f: immutable.Seq[Rejection] ⇒ RouteResult): Directive0 = mapRouteResultPF { case RouteResult.Rejected(rejections) ⇒ f(rejections) } + /** + * @group basic + */ def recoverRejectionsWith(f: immutable.Seq[Rejection] ⇒ Future[RouteResult]): Directive0 = mapRouteResultWithPF { case RouteResult.Rejected(rejections) ⇒ f(rejections) } + /** + * @group basic + */ def mapRejections(f: immutable.Seq[Rejection] ⇒ immutable.Seq[Rejection]): Directive0 = recoverRejections(rejections ⇒ RouteResult.Rejected(f(rejections))) + /** + * @group basic + */ def mapResponse(f: HttpResponse ⇒ HttpResponse): Directive0 = mapRouteResultPF { case RouteResult.Complete(response) ⇒ RouteResult.Complete(f(response)) } + /** + * @group basic + */ def mapResponseEntity(f: ResponseEntity ⇒ ResponseEntity): Directive0 = mapResponse(_ mapEntity f) + /** + * @group basic + */ def mapResponseHeaders(f: immutable.Seq[HttpHeader] ⇒ immutable.Seq[HttpHeader]): Directive0 = mapResponse(_ mapHeaders f) /** * A Directive0 that always passes the request on to its inner route * (i.e. does nothing with the request or the response). + * + * @group basic */ def pass: Directive0 = Directive.Empty /** * Injects the given value into a directive. + * + * @group basic */ def provide[T](value: T): Directive1[T] = tprovide(Tuple1(value)) /** * Injects the given values into a directive. + * + * @group basic */ def tprovide[L: Tuple](values: L): Directive[L] = Directive { _(values) } /** * Extracts a single value using the given function. + * + * @group basic */ def extract[T](f: RequestContext ⇒ T): Directive1[T] = textract(ctx ⇒ Tuple1(f(ctx))) /** * Extracts a number of values using the given function. + * + * @group basic */ def textract[L: Tuple](f: RequestContext ⇒ L): Directive[L] = Directive { inner ⇒ ctx ⇒ inner(f(ctx))(ctx) } @@ -91,6 +147,8 @@ trait BasicDirectives { /** * Adds a TransformationRejection cancelling all rejections equal to the given one * to the list of rejections potentially coming back from the inner route. + * + * @group basic */ def cancelRejection(rejection: Rejection): Directive0 = cancelRejections(_ == rejection) @@ -98,6 +156,8 @@ trait BasicDirectives { /** * Adds a TransformationRejection cancelling all rejections of one of the given classes * to the list of rejections potentially coming back from the inner route. + * + * @group basic */ def cancelRejections(classes: Class[_]*): Directive0 = 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 * to the list of rejections potentially coming back from the inner route. + * + * @group basic */ def cancelRejections(cancelFilter: Rejection ⇒ Boolean): Directive0 = mapRejections(_ :+ TransformationRejection(_ filterNot cancelFilter)) /** * Transforms the unmatchedPath of the RequestContext using the given function. + * + * @group basic */ def mapUnmatchedPath(f: Uri.Path ⇒ Uri.Path): Directive0 = mapRequestContext(_ mapUnmatchedPath f) /** * Extracts the yet unmatched path from the RequestContext. + * + * @group basic */ def extractUnmatchedPath: Directive1[Uri.Path] = BasicDirectives._extractUnmatchedPath /** * Extracts the current [[HttpRequest]] instance. + * + * @group basic */ def extractRequest: Directive1[HttpRequest] = BasicDirectives._extractRequest /** * Extracts the complete request URI. + * + * @group basic */ def extractUri: Directive1[Uri] = BasicDirectives._extractUri /** * Runs its inner route with the given alternative [[scala.concurrent.ExecutionContextExecutor]]. + * + * @group basic */ def withExecutionContext(ec: ExecutionContextExecutor): Directive0 = mapRequestContext(_ withExecutionContext ec) /** * Extracts the [[scala.concurrent.ExecutionContextExecutor]] from the [[akka.http.scaladsl.server.RequestContext]]. + * + * @group basic */ def extractExecutionContext: Directive1[ExecutionContextExecutor] = BasicDirectives._extractExecutionContext /** * Runs its inner route with the given alternative [[akka.stream.Materializer]]. + * + * @group basic */ def withMaterializer(materializer: Materializer): Directive0 = mapRequestContext(_ withMaterializer materializer) /** * Extracts the [[akka.stream.Materializer]] from the [[akka.http.scaladsl.server.RequestContext]]. + * + * @group basic */ def extractMaterializer: Directive1[Materializer] = BasicDirectives._extractMaterializer /** * Runs its inner route with the given alternative [[akka.event.LoggingAdapter]]. + * + * @group basic */ def withLog(log: LoggingAdapter): Directive0 = mapRequestContext(_ withLog log) /** * Extracts the [[akka.event.LoggingAdapter]] from the [[akka.http.scaladsl.server.RequestContext]]. + * + * @group basic */ def extractLog: Directive1[LoggingAdapter] = BasicDirectives._extractLog /** * Runs its inner route with the given alternative [[RoutingSettings]]. + * + * @group basic */ def withSettings(settings: RoutingSettings): Directive0 = mapRequestContext(_ withRoutingSettings settings) /** * Runs the inner route with settings mapped by the given function. + * + * @group basic */ def mapSettings(f: RoutingSettings ⇒ RoutingSettings): Directive0 = mapRequestContext(ctx ⇒ ctx.withRoutingSettings(f(ctx.settings))) /** * Extracts the [[RoutingSettings]] from the [[akka.http.scaladsl.server.RequestContext]]. + * + * @group basic */ def extractSettings: Directive1[RoutingSettings] = BasicDirectives._extractSettings /** * Extracts the [[akka.http.scaladsl.settings.ParserSettings]] from the [[akka.http.scaladsl.server.RequestContext]]. + * + * @group basic */ def extractParserSettings: Directive1[ParserSettings] = BasicDirectives._extractParserSettings /** * Extracts the [[akka.http.scaladsl.server.RequestContext]] itself. + * + * @group basic */ def extractRequestContext: Directive1[RequestContext] = BasicDirectives._extractRequestContext } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CacheConditionDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CacheConditionDirectives.scala index 818888fde3..7320618ed2 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CacheConditionDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CacheConditionDirectives.scala @@ -12,6 +12,10 @@ import HttpMethods._ import StatusCodes._ import EntityTag._ +/** + * @groupname cachecondition Cache condition directives + * @groupprio cachecondition 20 + */ trait CacheConditionDirectives { import BasicDirectives._ import RouteDirectives._ @@ -26,6 +30,8 @@ trait CacheConditionDirectives { * 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(...)` * 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) @@ -39,6 +45,8 @@ trait CacheConditionDirectives { * 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(...)` * 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)) @@ -52,6 +60,8 @@ trait CacheConditionDirectives { * 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(...)` * 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)) @@ -65,6 +75,8 @@ trait CacheConditionDirectives { * 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(...)` * 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 addResponseHeaders: Directive0 = diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala index ca64e384ba..1b538e4047 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala @@ -12,6 +12,10 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.coding._ import akka.http.impl.util._ +/** + * @groupname coding Coding directives + * @groupprio coding 50 + */ trait CodingDirectives { import BasicDirectives._ import MiscDirectives._ @@ -23,6 +27,8 @@ trait CodingDirectives { /** * Rejects the request with an UnacceptedResponseEncodingRejection * if the given response encoding is not accepted by the client. + * + * @group coding */ def responseEncodingAccepted(encoding: HttpEncoding): Directive0 = extractRequest.flatMap { request ⇒ @@ -37,6 +43,8 @@ trait CodingDirectives { * * If the `Accept-Encoding` header is missing or empty or specifies an encoding other than * identity, gzip or deflate then no encoding is used. + * + * @group coding */ def encodeResponse: Directive0 = _encodeResponse(DefaultEncodeResponseEncoders) @@ -51,6 +59,8 @@ trait CodingDirectives { * * 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. + * + * @group coding */ def encodeResponseWith(first: Encoder, more: Encoder*): Directive0 = _encodeResponse(immutable.Seq(first +: more: _*)) @@ -60,6 +70,8 @@ trait CodingDirectives { /** * Decodes the incoming request using the given Decoder. * If the request encoding doesn't match the request is rejected with an `UnsupportedRequestEncodingRejection`. + * + * @group coding */ def decodeRequestWith(decoder: Decoder): Directive0 = { def applyDecoder = @@ -85,6 +97,8 @@ trait CodingDirectives { /** * Rejects the request with an UnsupportedRequestEncodingRejection if its encoding doesn't match the given one. + * + * @group coding */ def requestEncodedWith(encoding: HttpEncoding): Directive0 = extract(_.request.encoding).flatMap { @@ -97,6 +111,8 @@ trait CodingDirectives { * encoders. If the request encoding doesn't match one of the given encoders * the request is rejected with an `UnsupportedRequestEncodingRejection`. * If no decoders are given the default encoders (`Gzip`, `Deflate`, `NoCoding`) are used. + * + * @group coding */ def decodeRequestWith(decoders: Decoder*): Directive0 = theseOrDefault(decoders).map(decodeRequestWith).reduce(_ | _) @@ -105,6 +121,8 @@ trait CodingDirectives { * Decompresses the incoming request if it is `gzip` or `deflate` compressed. * Uncompressed requests are passed through untouched. * If the request encoded with another encoding the request is rejected with an `UnsupportedRequestEncodingRejection`. + * + * @group coding */ def decodeRequest: Directive0 = decodeRequestWith(DefaultCoders: _*) @@ -112,6 +130,8 @@ trait CodingDirectives { /** * 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. + * + * @group coding */ def withPrecompressedMediaTypeSupport: Directive0 = mapResponse { response ⇒ diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala index c58de48ac5..d69e4f13ef 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala @@ -9,6 +9,10 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers._ import akka.http.impl.util._ +/** + * @groupname cookie Cookie directives + * @groupprio cookie 30 + */ trait CookieDirectives { import HeaderDirectives._ import RespondWithDirectives._ @@ -17,6 +21,8 @@ trait CookieDirectives { /** * Extracts the [[HttpCookiePair]] with the given name. If the cookie is not present the * request is rejected with a respective [[MissingCookieRejection]]. + * + * @group cookie */ def cookie(name: String): Directive1[HttpCookiePair] = headerValue(findCookie(name)) | reject(MissingCookieRejection(name)) @@ -24,6 +30,8 @@ trait CookieDirectives { /** * Extracts the [[HttpCookiePair]] with the given name as an `Option[HttpCookiePair]`. * If the cookie is not present a value of `None` is extracted. + * + * @group cookie */ def optionalCookie(name: String): Directive1[Option[HttpCookiePair]] = optionalHeaderValue(findCookie(name)) @@ -35,12 +43,16 @@ trait CookieDirectives { /** * Adds a [[Set-Cookie]] response header with the given cookies. + * + * @group cookie */ def setCookie(first: HttpCookie, more: HttpCookie*): Directive0 = respondWithHeaders((first :: more.toList).map(`Set-Cookie`(_))) /** * Adds a [[Set-Cookie]] response header expiring the given cookies. + * + * @group cookie */ def deleteCookie(first: HttpCookie, more: HttpCookie*): Directive0 = 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. + * + * @group cookie */ def deleteCookie(name: String, domain: String = "", path: String = ""): Directive0 = deleteCookie(HttpCookie(name, "", domain = domain.toOption, path = path.toOption)) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/DebuggingDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/DebuggingDirectives.scala index c878ffea6e..03805f04e0 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/DebuggingDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/DebuggingDirectives.scala @@ -9,11 +9,17 @@ import akka.event.Logging._ import akka.event.LoggingAdapter import akka.http.scaladsl.model._ +/** + * @groupname debugging Debugging directives + * @groupprio debugging 40 + */ trait DebuggingDirectives { import BasicDirectives._ /** * Produces a log entry for every incoming request. + * + * @group debugging */ def logRequest(magnet: LoggingMagnet[HttpRequest ⇒ Unit]): Directive0 = extractRequestContext.flatMap { ctx ⇒ @@ -23,6 +29,8 @@ trait DebuggingDirectives { /** * Produces a log entry for every [[RouteResult]]. + * + * @group debugging */ def logResult(magnet: LoggingMagnet[RouteResult ⇒ Unit]): Directive0 = extractRequestContext.flatMap { ctx ⇒ @@ -34,6 +42,8 @@ trait DebuggingDirectives { /** * Produces a log entry for every incoming request and [[RouteResult]]. + * + * @group debugging */ def logRequestResult(magnet: LoggingMagnet[HttpRequest ⇒ RouteResult ⇒ Unit]): Directive0 = extractRequestContext.flatMap { ctx ⇒ diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ExecutionDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ExecutionDirectives.scala index 009a4a6b55..b803e22947 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ExecutionDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ExecutionDirectives.scala @@ -11,12 +11,18 @@ import scala.util.control.NonFatal import akka.http.scaladsl.util.FastFuture import akka.http.scaladsl.util.FastFuture._ +/** + * @groupname execution Execution directives + * @groupprio execution 60 + */ trait ExecutionDirectives { import BasicDirectives._ /** * Transforms exceptions thrown during evaluation of its inner route using the given * [[akka.http.scaladsl.server.ExceptionHandler]]. + * + * @group execution */ def handleExceptions(handler: ExceptionHandler): Directive0 = Directive { innerRouteBuilder ⇒ @@ -33,6 +39,8 @@ trait ExecutionDirectives { /** * Transforms rejections produced by its inner route using the given * [[akka.http.scaladsl.server.RejectionHandler]]. + * + * @group execution */ def handleRejections(handler: RejectionHandler): Directive0 = extractRequestContext flatMap { ctx ⇒ @@ -55,4 +63,4 @@ trait ExecutionDirectives { } } -object ExecutionDirectives extends ExecutionDirectives \ No newline at end of file +object ExecutionDirectives extends ExecutionDirectives diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala index 9da99b9b0e..23c7d43466 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala @@ -19,6 +19,10 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers._ import akka.http.impl.util._ +/** + * @groupname fileandresource File and resource directives + * @groupprio fileandresource 70 + */ trait FileAndResourceDirectives { import CacheConditionDirectives._ import MethodDirectives._ @@ -30,6 +34,8 @@ trait FileAndResourceDirectives { /** * Completes GET requests with the content of the given file. * If the file cannot be found or read the request is rejected. + * + * @group fileandresource */ def getFromFile(fileName: String)(implicit resolver: ContentTypeResolver): Route = getFromFile(new File(fileName)) @@ -37,6 +43,8 @@ trait FileAndResourceDirectives { /** * Completes GET requests with the content of the given file. * If the file cannot be found or read the request is rejected. + * + * @group fileandresource */ def getFromFile(file: File)(implicit resolver: ContentTypeResolver): Route = getFromFile(file, resolver(file.getName)) @@ -44,6 +52,8 @@ trait FileAndResourceDirectives { /** * Completes GET requests with the content of the given file. * If the file cannot be found or read the request is rejected. + * + * @group fileandresource */ def getFromFile(file: File, contentType: ContentType): Route = get { @@ -72,6 +82,8 @@ trait FileAndResourceDirectives { /** * 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. + * + * @group fileandresource */ def getFromResource(resourceName: String)(implicit resolver: ContentTypeResolver): Route = getFromResource(resourceName, resolver(resourceName)) @@ -79,6 +91,8 @@ trait FileAndResourceDirectives { /** * 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. + * + * @group fileandresource */ def getFromResource(resourceName: String, contentType: ContentType, classLoader: ClassLoader = defaultClassLoader): Route = if (!resourceName.endsWith("/")) @@ -104,6 +118,8 @@ trait FileAndResourceDirectives { /** * Completes GET requests with the content of a file underneath the given directory. * If the file cannot be read the Route rejects the request. + * + * @group fileandresource */ def getFromDirectory(directoryName: String)(implicit resolver: ContentTypeResolver): Route = { val base = withTrailingSlash(directoryName) @@ -120,6 +136,8 @@ trait FileAndResourceDirectives { /** * 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]`. + * + * @group fileandresource */ def listDirectoryContents(directories: String*)(implicit renderer: DirectoryRenderer): Route = get { @@ -147,6 +165,8 @@ trait FileAndResourceDirectives { /** * Same as `getFromBrowseableDirectories` with only one directory. + * + * @group fileandresource */ def getFromBrowseableDirectory(directory: String)(implicit renderer: DirectoryRenderer, resolver: ContentTypeResolver): Route = 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 * served as browseable listings. + * + * @group fileandresource */ def getFromBrowseableDirectories(directories: String*)(implicit renderer: DirectoryRenderer, resolver: ContentTypeResolver): Route = { 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 * "resource directory". * 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 = { val base = if (directoryName.isEmpty) "" else withTrailingSlash(directoryName) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileUploadDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileUploadDirectives.scala index da7caa4b03..b7ba4718c4 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileUploadDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FileUploadDirectives.scala @@ -12,6 +12,10 @@ import scala.concurrent.Future import scala.util.{ Failure, Success } import akka.stream.scaladsl._ +/** + * @groupname fileupload File upload directives + * @groupprio fileupload 80 + */ trait FileUploadDirectives { 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 * 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. + * + * @group fileupload */ def uploadedFile(fieldName: String): Directive1[(FileInfo, File)] = 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, * if there are multiple file parts with the same name, the first one will be used and the subsequent * ones ignored. + * + * @group fileupload */ def fileUpload(fieldName: String): Directive1[(FileInfo, Source[ByteString, Any])] = entity(as[Multipart.FormData]).flatMap { formData ⇒ diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FormFieldDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FormFieldDirectives.scala index 2aba80c7da..bff78d9a12 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FormFieldDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FormFieldDirectives.scala @@ -16,33 +16,47 @@ import scala.collection.immutable import scala.concurrent.Future import scala.util.{ Failure, Success } +/** + * @groupname form Form field directives + * @groupprio form 90 + */ trait FormFieldDirectives extends ToNameReceptacleEnhancements { import FormFieldDirectives._ /** * Extracts HTTP form fields from the request as a ``Map[String, String]``. + * + * @group form */ def formFieldMap: Directive1[Map[String, String]] = _formFieldMap /** * Extracts HTTP form fields from the request as a ``Map[String, List[String]]``. + * + * @group form */ def formFieldMultiMap: Directive1[Map[String, List[String]]] = _formFieldMultiMap /** * Extracts HTTP form fields from the request as a ``Seq[(String, String)]``. + * + * @group form */ def formFieldSeq: Directive1[immutable.Seq[(String, String)]] = _formFieldSeq /** * Extracts an HTTP form field from the request. * Rejects the request if the defined form field matcher(s) don't match. + * + * @group form */ def formField(pdm: FieldMagnet): pdm.Out = pdm() /** * Extracts a number of HTTP form field from the request. * Rejects the request if the defined form field matcher(s) don't match. + * + * @group form */ def formFields(pdm: FieldMagnet): pdm.Out = pdm() diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala index db40814522..c0ce5b49fc 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala @@ -13,11 +13,17 @@ import akka.http.scaladsl.util.FastFuture._ // format: OFF +/** + * @groupname future Future directives + * @groupprio future 100 + */ trait FutureDirectives { /** * "Unwraps" a `Future[T]` and runs the inner route after future * completion with the future's value as an extraction of type `Try[T]`. + * + * @group future */ def onComplete[T](future: ⇒ Future[T]): Directive1[Try[T]] = Directive { inner ⇒ ctx ⇒ @@ -32,6 +38,8 @@ trait FutureDirectives { * ExceptionHandler. * If type `T` is already a Tuple it is directly expanded into the respective * number of extractions. + * + * @group future */ 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 * (This directive therefore requires a marshaller for the futures type to be * implicitly available.) + * + * @group future */ def completeOrRecoverWith(magnet: CompleteOrRecoverWithMagnet): Directive1[Throwable] = magnet.directive } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala index ba3e7bf53f..eaf311657f 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala @@ -16,6 +16,10 @@ import akka.http.scaladsl.server.util.ClassMagnet import akka.http.scaladsl.model._ import akka.http.impl.util._ +/** + * @groupname header Header directives + * @groupprio header 110 + */ trait HeaderDirectives { import BasicDirectives._ 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 * 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]]. + * + * @group header */ def headerValue[T](f: HttpHeader ⇒ Option[T]): Directive1[T] = { 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 * request is rejected with an empty rejection set. + * + * @group header */ 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. * 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) /** * 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]]. + * + * @group header */ def headerValueByName(headerName: String): Directive1[String] = 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]] * and provide a companion extending [[ModeledCustomHeaderCompanion]]. + * + * @group header */ def headerValueByType[T](magnet: HeaderMagnet[T]): Directive1[T] = headerValuePF(magnet.extractPF) | reject(MissingHeaderRejection(magnet.runtimeClass.getSimpleName)) @@ -73,6 +87,8 @@ trait HeaderDirectives { * Extracts an optional HTTP header value using the given function. * If the given function throws an exception the request is rejected * with a [[akka.http.scaladsl.server.MalformedHeaderRejection]]. + * + * @group header */ def optionalHeaderValue[T](f: HttpHeader ⇒ Option[T]): Directive1[Option[T]] = headerValue(f).map(Some(_): Option[T]).recoverPF { @@ -84,18 +100,24 @@ trait HeaderDirectives { * Extracts an optional HTTP header value using the given partial function. * If the given function throws an exception the request is rejected * with a [[akka.http.scaladsl.server.MalformedHeaderRejection]]. + * + * @group header */ def optionalHeaderValuePF[T](pf: PartialFunction[HttpHeader, T]): Directive1[Option[T]] = optionalHeaderValue(pf.lift) /** * Extracts the value of the optional HTTP request header with the given name. + * + * @group header */ def optionalHeaderValueByName(headerName: Symbol): Directive1[Option[String]] = optionalHeaderValueByName(headerName.name) /** * Extracts the value of the optional HTTP request header with the given name. + * + * @group header */ def optionalHeaderValueByName(headerName: String): Directive1[Option[String]] = { val lowerCaseName = headerName.toLowerCase @@ -109,6 +131,8 @@ trait HeaderDirectives { * * Custom headers will only be matched by this directive if they extend [[ModeledCustomHeader]] * and provide a companion extending [[ModeledCustomHeaderCompanion]]. + * + * @group header */ def optionalHeaderValueByType[T <: HttpHeader](magnet: HeaderMagnet[T]): Directive1[Option[T]] = optionalHeaderValuePF(magnet.extractPF) @@ -156,4 +180,4 @@ trait LowPriorityHeaderMagnetImplicits { val runtimeClass: Class[T] = tag.runtimeClass.asInstanceOf[Class[T]] val extractPF: PartialFunction[Any, T] = { case x: T ⇒ x } } -} \ No newline at end of file +} diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HostDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HostDirectives.scala index d69f2ee9d4..775adff8da 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HostDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/HostDirectives.scala @@ -8,23 +8,33 @@ package directives import scala.util.matching.Regex import akka.http.impl.util._ +/** + * @groupname host Host directives + * @groupprio host 110 + */ trait HostDirectives { import BasicDirectives._ import RouteDirectives._ /** * Extracts the hostname part of the Host request header value. + * + * @group host */ def extractHost: Directive1[String] = HostDirectives._extractHost /** * Rejects all requests with a host name different from the given ones. + * + * @group host */ def host(hostNames: String*): Directive0 = host(hostNames.contains(_)) //#require-host /** * Rejects all requests for whose host name the given predicate function returns false. + * + * @group host */ 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. * 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. + * + * @group host */ def host(regex: Regex): Directive1[String] = { def forFunc(regexMatch: String ⇒ Option[String]): Directive1[String] = { diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MarshallingDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MarshallingDirectives.scala index 9aea4ee3f5..bf0d60e0f3 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MarshallingDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MarshallingDirectives.scala @@ -11,6 +11,10 @@ import akka.http.scaladsl.marshalling.ToResponseMarshaller import akka.http.scaladsl.unmarshalling.{ Unmarshaller, FromRequestUnmarshaller } import akka.http.impl.util._ +/** + * @groupname marshalling Marshalling directives + * @groupprio marshalling 120 + */ trait MarshallingDirectives { import BasicDirectives._ import FutureDirectives._ @@ -20,6 +24,8 @@ trait MarshallingDirectives { * 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]] * produced by the unmarshaller. + * + * @group marshalling */ def entity[T](um: FromRequestUnmarshaller[T]): Directive1[T] = extractRequestContext.flatMap[Tuple1[T]] { ctx ⇒ @@ -36,12 +42,16 @@ trait MarshallingDirectives { /** * Returns the in-scope [[FromRequestUnmarshaller]] for the given type. + * + * @group marshalling */ 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. * You can use it do decouple marshaller resolution from request completion. + * + * @group marshalling */ def completeWith[T](marshaller: ToResponseMarshaller[T])(inner: (T ⇒ Unit) ⇒ Unit): Route = extractRequestContext { ctx ⇒ @@ -55,12 +65,16 @@ trait MarshallingDirectives { /** * Returns the in-scope Marshaller for the given type. + * + * @group marshalling */ 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 * 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 = entity(um) { a ⇒ complete(f(a)) } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala index 9b7be89713..5dffa97171 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala @@ -8,6 +8,10 @@ package directives import akka.http.scaladsl.model.{ StatusCodes, HttpMethod } import akka.http.scaladsl.model.HttpMethods._ +/** + * @groupname method Method directives + * @groupprio method 130 + */ trait MethodDirectives { import BasicDirectives._ import RouteDirectives._ @@ -16,47 +20,65 @@ trait MethodDirectives { /** * Rejects all non-DELETE requests. + * + * @group method */ def delete: Directive0 = _delete /** * Rejects all non-GET requests. + * + * @group method */ def get: Directive0 = _get /** * Rejects all non-HEAD requests. + * + * @group method */ def head: Directive0 = _head /** * Rejects all non-OPTIONS requests. + * + * @group method */ def options: Directive0 = _options /** * Rejects all non-PATCH requests. + * + * @group method */ def patch: Directive0 = _patch /** * Rejects all non-POST requests. + * + * @group method */ def post: Directive0 = _post /** * Rejects all non-PUT requests. + * + * @group method */ def put: Directive0 = _put /** * Extracts the request method. + * + * @group method */ def extractMethod: Directive1[HttpMethod] = _extractMethod //#method /** * Rejects all requests whose HTTP method does not match the given one. + * + * @group method */ def method(httpMethod: HttpMethod): Directive0 = extractMethod.flatMap[Unit] { @@ -73,6 +95,8 @@ trait MethodDirectives { * This directive is useful for: * - 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 + * + * @group method */ def overrideMethodWithParameter(paramName: String): Directive0 = parameter(paramName?) flatMap { diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala index 1e5fba62a0..8d33d10b0e 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala @@ -8,12 +8,18 @@ package directives import akka.http.scaladsl.model._ import headers._ +/** + * @groupname misc Miscellaneous directives + * @groupprio misc 140 + */ trait MiscDirectives { import RouteDirectives._ /** * Checks the given condition before running its inner route. * If the condition fails the route is rejected with a [[ValidationRejection]]. + * + * @group misc */ def validate(check: ⇒ Boolean, errorMsg: String): Directive0 = 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 * (in that order of priority). + * + * @group misc */ def extractClientIP: Directive1[RemoteAddress] = MiscDirectives._extractClientIP /** * Rejects if the request entity is non-empty. + * + * @group misc */ def requestEntityEmpty: Directive0 = MiscDirectives._requestEntityEmpty /** * Rejects with a [[RequestEntityExpectedRejection]] if the request entity is empty. * Non-empty requests are passed on unchanged to the inner route. + * + * @group misc */ def requestEntityPresent: Directive0 = MiscDirectives._requestEntityPresent @@ -39,6 +51,8 @@ trait MiscDirectives { * Converts responses with an empty entity into (empty) rejections. * This way you can, for example, have the marshalling of a ''None'' option * be treated as if the request could not be matched. + * + * @group misc */ def rejectEmptyResponse: Directive0 = MiscDirectives._rejectEmptyResponse @@ -50,6 +64,8 @@ trait MiscDirectives { * If there are several best language alternatives that the client * has equal preference for (even if this preference is zero!) * the order of the arguments is used as a tie breaker (First one wins). + * + * @group misc */ def selectPreferredLanguage(first: Language, more: Language*): Directive1[Language] = BasicDirectives.extractRequest.map { request ⇒ diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala index c4bb83339e..041e4c9573 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala @@ -11,21 +11,31 @@ import scala.util.{ Failure, Success } import akka.http.scaladsl.common._ import akka.http.impl.util._ +/** + * @groupname param Parameter directives + * @groupprio param 150 + */ trait ParameterDirectives extends ToNameReceptacleEnhancements { import ParameterDirectives._ /** * Extracts the request's query parameters as a `Map[String, String]`. + * + * @group param */ def parameterMap: Directive1[Map[String, String]] = _parameterMap /** * Extracts the request's query parameters as a `Map[String, List[String]]`. + * + * @group param */ def parameterMultiMap: Directive1[Map[String, List[String]]] = _parameterMultiMap /** * Extracts the request's query parameters as a `Seq[(String, String)]`. + * + * @group param */ 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. * * As a workaround add an `import ParameterDirectives.ParamMagnet` or use Scala 2.11.x. + * + * @group param */ 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. * * As a workaround add an `import ParameterDirectives.ParamMagnet` or use Scala 2.11.x. + * + * @group param */ def parameters(pdm: ParamMagnet): pdm.Out = pdm() @@ -170,4 +184,4 @@ object ParameterDirectives extends ParameterDirectives { at[Directive[TA], P] { (a, t) ⇒ a & pdef(t) } } } -} \ No newline at end of file +} diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/PathDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/PathDirectives.scala index ac74b686fd..b566a15702 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/PathDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/PathDirectives.scala @@ -9,6 +9,10 @@ import akka.http.scaladsl.common.ToNameReceptacleEnhancements import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.model.Uri.Path +/** + * @groupname path Path directives + * @groupprio path 170 + */ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction with ToNameReceptacleEnhancements { import BasicDirectives._ 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. * The matcher has to match the remaining path completely. * 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) @@ -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. * 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. + * + * @group path */ 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). * 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. + * + * @group path */ def rawPathPrefix[L](pm: PathMatcher[L]): Directive[L] = { 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 * 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) @@ -52,6 +64,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w * 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 * actually "consumed". + * + * @group path */ def rawPathPrefixTest[L](pm: PathMatcher[L]): Directive[L] = { 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. * 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`! + * + * @group path */ def pathSuffix[L](pm: PathMatcher[L]): Directive[L] = { implicit val LIsTuple = pm.ev @@ -81,6 +97,8 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w * actually "consumed". * 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`! + * + * @group path */ def pathSuffixTest[L](pm: PathMatcher[L]): Directive[L] = { 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, * or said differently: only passes on the request to its inner route if the request path * has been matched completely. + * + * @group path */ def pathEnd: Directive0 = rawPathPrefix(PathEnd) @@ -124,12 +144,16 @@ trait PathDirectives extends PathMatchers with ImplicitPathMatcherConstruction w * * For further information, refer to: * @see [[http://googlewebmastercentral.blogspot.de/2010/04/to-slash-or-not-to-slash.html]] + * + * @group path */ def pathEndOrSingleSlash: Directive0 = rawPathPrefix(Slash.? ~ PathEnd) /** * Only passes on the request to its inner route if the request path * consists of exactly one remaining slash. + * + * @group path */ 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. * * '''Caveat''': [[path]] without trailing slash and [[pathEnd]] directives will not match inside of this directive. + * + * @group path */ def redirectToTrailingSlashIfMissing(redirectionType: StatusCodes.Redirection): Directive0 = 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. * * '''Caveat''': [[pathSingleSlash]] directive will not match inside of this directive. + * + * @group path */ def redirectToNoTrailingSlashIfPresent(redirectionType: StatusCodes.Redirection): Directive0 = extractUri.flatMap { uri ⇒ diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RangeDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RangeDirectives.scala index 172c6eb036..bfc841750f 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RangeDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RangeDirectives.scala @@ -16,6 +16,10 @@ import akka.util.ByteString import akka.stream.SourceShape import akka.stream.OverflowStrategy +/** + * @groupname range Range directives + * @groupprio range 180 + */ trait RangeDirectives { import akka.http.scaladsl.server.directives.BasicDirectives._ 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. * * @see [[https://tools.ietf.org/html/rfc7233]] + * + * @group range */ def withRangeSupport: Directive0 = extractRequestContext.flatMap { ctx ⇒ diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala index 72df156061..3784cbd799 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala @@ -4,28 +4,40 @@ package directives import akka.http.scaladsl.model._ import scala.collection.immutable +/** + * @groupname response Response directives + * @groupprio response 190 + */ trait RespondWithDirectives { import BasicDirectives._ /** * Unconditionally adds the given response header to all HTTP responses of its inner Route. + * + * @group response */ def respondWithHeader(responseHeader: HttpHeader): Directive0 = respondWithHeaders(responseHeader) /** * 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. + * + * @group response */ def respondWithDefaultHeader(responseHeader: HttpHeader): Directive0 = respondWithDefaultHeaders(responseHeader) /** * Unconditionally adds the given response headers to all HTTP responses of its inner Route. + * + * @group response */ def respondWithHeaders(responseHeaders: HttpHeader*): Directive0 = respondWithHeaders(responseHeaders.toList) /** * Unconditionally adds the given response headers to all HTTP responses of its inner Route. + * + * @group response */ def respondWithHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 = mapResponseHeaders(responseHeaders ++ _) @@ -33,12 +45,17 @@ trait RespondWithDirectives { /** * Adds the given response headers to all HTTP responses of its inner Route, * if a header already exists it is not added again. + * + * @group response */ def respondWithDefaultHeaders(responseHeaders: HttpHeader*): Directive0 = 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. + * + * @group response */ def respondWithDefaultHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 = mapResponse(_.withDefaultHeaders(responseHeaders)) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala index 7a37a38c3a..c1c7cf612e 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala @@ -9,21 +9,31 @@ import akka.http.scaladsl.marshalling.ToResponseMarshallable import akka.http.scaladsl.model._ import StatusCodes._ +/** + * @groupname route Route directives + * @groupprio route 200 + */ trait RouteDirectives { /** * Rejects the request with an empty set of rejections. + * + * @group route */ def reject: StandardRoute = RouteDirectives._reject /** * Rejects the request with the given rejections. + * + * @group route */ def reject(rejections: Rejection*): StandardRoute = StandardRoute(_.reject(rejections: _*)) /** * Completes the request with redirection response of the given type to the given URI. + * + * @group route */ def redirect(uri: Uri, redirectionType: Redirection): StandardRoute = StandardRoute { @@ -42,6 +52,8 @@ trait RouteDirectives { /** * Completes the request using the given arguments. + * + * @group route */ def complete(m: ⇒ ToResponseMarshallable): StandardRoute = 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` * directive and its ExceptionHandler. + * + * @group route */ def failWith(error: Throwable): StandardRoute = StandardRoute(_.fail(error)) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SchemeDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SchemeDirectives.scala index 098671dc2c..e8f7df06a8 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SchemeDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SchemeDirectives.scala @@ -5,16 +5,24 @@ package akka.http.scaladsl.server package directives +/** + * @groupname scheme Scheme directives + * @groupprio scheme 210 + */ trait SchemeDirectives { import BasicDirectives._ /** * Extracts the Uri scheme from the request. + * + * @group scheme */ def extractScheme: Directive1[String] = SchemeDirectives._extractScheme /** * Rejects all requests whose Uri scheme does not match the given one. + * + * @group scheme */ def scheme(name: String): Directive0 = extractScheme.require(_ == name, SchemeRejection(name)) & cancelRejections(classOf[SchemeRejection]) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala index 6cc08cb2f0..16cab40e0e 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala @@ -20,6 +20,9 @@ import scala.util.{Try, Success} * and [[Authorization]]. Most prominently, HTTP Basic authentication as defined in RFC 2617. * * See: RFC 2617. + * + * @groupname security Security directives + * @groupprio security 220 */ trait SecurityDirectives { import BasicDirectives._ @@ -31,25 +34,41 @@ trait SecurityDirectives { /** * The result of an HTTP authentication attempt is either the user object or * an HttpChallenge to present to the browser. + * + * @group security */ type AuthenticationResult[+T] = Either[HttpChallenge, T] //#authentication-result //#authenticator + /** + * @group security + */ type Authenticator[T] = Credentials ⇒ Option[T] //#authenticator //#async-authenticator + /** + * @group security + */ type AsyncAuthenticator[T] = Credentials ⇒ Future[Option[T]] //#async-authenticator //#authenticator-pf + /** + * @group security + */ type AuthenticatorPF[T] = PartialFunction[Credentials, T] //#authenticator-pf //#async-authenticator-pf + /** + * @group security + */ type AsyncAuthenticatorPF[T] = PartialFunction[Credentials, Future[T]] //#async-authenticator-pf /** * Extracts the potentially present [[HttpCredentials]] provided with the request's [[Authorization]] header. + * + * @group security */ def extractCredentials: Directive1[Option[HttpCredentials]] = 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]`. * The given authenticator determines whether the credentials in the request are valid * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateBasic[T](realm: String, authenticator: Authenticator[T]): AuthenticationDirective[T] = authenticateBasicAsync(realm, cred ⇒ FastFuture.successful(authenticator(cred))) @@ -66,6 +87,8 @@ trait SecurityDirectives { * Wraps the inner route with Http Basic authentication support. * The given authenticator determines whether the credentials in the request are valid * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateBasicAsync[T](realm: String, authenticator: AsyncAuthenticator[T]): AuthenticationDirective[T] = extractExecutionContext.flatMap { implicit ec ⇒ @@ -81,6 +104,8 @@ trait SecurityDirectives { * A directive that wraps the inner route with Http Basic authentication support. * The given authenticator determines whether the credentials in the request are valid * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateBasicPF[T](realm: String, authenticator: AuthenticatorPF[T]): AuthenticationDirective[T] = authenticateBasic(realm, authenticator.lift) @@ -89,6 +114,8 @@ trait SecurityDirectives { * A directive that wraps the inner route with Http Basic authentication support. * The given authenticator determines whether the credentials in the request are valid * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateBasicPFAsync[T](realm: String, authenticator: AsyncAuthenticatorPF[T]): AuthenticationDirective[T] = extractExecutionContext.flatMap { implicit ec ⇒ @@ -101,6 +128,8 @@ trait SecurityDirectives { * 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 * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateOAuth2[T](realm: String, authenticator: Authenticator[T]): AuthenticationDirective[T] = 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. * The given authenticator determines whether the credentials in the request are valid * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateOAuth2Async[T](realm: String, authenticator: AsyncAuthenticator[T]): AuthenticationDirective[T] = extractExecutionContext.flatMap { implicit ec ⇒ @@ -124,6 +155,8 @@ trait SecurityDirectives { * 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 * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateOAuth2PF[T](realm: String, authenticator: AuthenticatorPF[T]): AuthenticationDirective[T] = authenticateOAuth2(realm, authenticator.lift) @@ -132,6 +165,8 @@ trait SecurityDirectives { * 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 * and, if so, which user object to supply to the inner route. + * + * @group security */ def authenticateOAuth2PFAsync[T](realm: String, authenticator: AsyncAuthenticatorPF[T]): AuthenticationDirective[T] = 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 * [[AuthenticationFailedRejection]] that contains this challenge to be added to the response. * + * @group security */ def authenticateOrRejectWithChallenge[T](authenticator: Option[HttpCredentials] ⇒ Future[AuthenticationResult[T]]): AuthenticationDirective[T] = extractExecutionContext.flatMap { implicit ec ⇒ @@ -162,6 +198,8 @@ trait SecurityDirectives { /** * Lifts an authenticator function into a directive. Same as `authenticateOrRejectWithChallenge` * but only applies the authenticator function with a certain type of credentials. + * + * @group security */ def authenticateOrRejectWithChallenge[C <: HttpCredentials: ClassTag, T]( authenticator: Option[C] ⇒ Future[AuthenticationResult[T]]): AuthenticationDirective[T] = @@ -170,12 +208,16 @@ trait SecurityDirectives { /** * Applies the given authorization check to the request. * If the check fails the route is rejected with an [[AuthorizationFailedRejection]]. + * + * @group security */ def authorize(check: ⇒ Boolean): Directive0 = authorize(_ ⇒ check) /** * Applies the given authorization check to the request. * If the check fails the route is rejected with an [[AuthorizationFailedRejection]]. + * + * @group security */ def authorize(check: RequestContext ⇒ Boolean): Directive0 = authorizeAsync(ctx => Future.successful(check(ctx))) @@ -184,6 +226,8 @@ trait SecurityDirectives { * Asynchronous version of [[authorize]]. * If the [[Future]] fails or is completed with `false` * authorization fails and the route is rejected with an [[AuthorizationFailedRejection]]. + * + * @group security */ def authorizeAsync(check: ⇒ Future[Boolean]): Directive0 = authorizeAsync(ctx => check) @@ -192,6 +236,8 @@ trait SecurityDirectives { * Asynchronous version of [[authorize]]. * If the [[Future]] fails or is completed with `false` * authorization fails and the route is rejected with an [[AuthorizationFailedRejection]]. + * + * @group security */ def authorizeAsync(check: RequestContext ⇒ Future[Boolean]): Directive0 = extractExecutionContext.flatMap { implicit ec ⇒ @@ -205,6 +251,8 @@ trait SecurityDirectives { /** * Creates a `Basic` [[HttpChallenge]] for the given realm. + * + * @group security */ def challengeFor(realm: String) = HttpChallenge(scheme = "Basic", realm = realm, params = Map.empty) } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/TimeoutDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/TimeoutDirectives.scala index 5b0f1fead0..5964538e5a 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/TimeoutDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/TimeoutDirectives.scala @@ -10,8 +10,15 @@ import akka.http.scaladsl.server.{ Directive, Directive0 } import scala.concurrent.duration.Duration +/** + * @groupname timeout Timeout directives + * @groupprio timeout 160 + */ trait TimeoutDirectives { + /** + * @group timeout + */ def withoutRequestTimeout: Directive0 = 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 * the previously set timeout has expired! + * + * @group timeout */ def withRequestTimeout(timeout: Duration): Directive0 = withRequestTimeout(timeout, None) @@ -31,6 +40,8 @@ trait TimeoutDirectives { * the previously set timeout has expired! * * @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 = withRequestTimeout(timeout, Some(handler)) @@ -42,6 +53,8 @@ trait TimeoutDirectives { * the previously set timeout has expired! * * @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 = Directive { inner ⇒ @@ -63,6 +76,8 @@ trait TimeoutDirectives { * * Due to the inherent raciness it is not guaranteed that the update will be applied before * the previously set timeout has expired! + * + * @group timeout */ def withRequestTimeoutResponse(handler: HttpRequest ⇒ HttpResponse): Directive0 = Directive { inner ⇒ @@ -76,4 +91,4 @@ trait TimeoutDirectives { } -object TimeoutDirectives extends TimeoutDirectives \ No newline at end of file +object TimeoutDirectives extends TimeoutDirectives diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala index a4d04c3c7d..711b3410cd 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala @@ -10,6 +10,10 @@ import scala.collection.immutable import akka.http.scaladsl.model.ws.{ UpgradeToWebSocket, Message } import akka.stream.scaladsl.Flow +/** + * @groupname websocket WebSocket directives + * @groupprio websocket 230 + */ trait WebSocketDirectives { import RouteDirectives._ import HeaderDirectives._ @@ -17,6 +21,8 @@ trait WebSocketDirectives { /** * Extract the [[UpgradeToWebSocket]] header if existent. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise. + * + * @group websocket */ def extractUpgradeToWebSocket: Directive1[UpgradeToWebSocket] = 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 * this is a WebSocket request. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise. + * + * @group websocket */ def extractOfferedWsProtocols: Directive1[immutable.Seq[String]] = extractUpgradeToWebSocket.map(_.requestedProtocols) /** * Handles WebSocket requests with the given handler and rejects other requests with an * [[ExpectedWebSocketRequestRejection]]. + * + * @group websocket */ def handleWebSocketMessages(handler: Flow[Message, Message, Any]): Route = 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 * rejects other requests with an [[ExpectedWebSocketRequestRejection]] or an [[UnsupportedWebSocketSubprotocolRejection]]. + * + * @group websocket */ def handleWebSocketMessagesForProtocol(handler: Flow[Message, Message, Any], subprotocol: String): Route = handleWebSocketMessagesForOptionalProtocol(handler, Some(subprotocol)) @@ -54,6 +66,8 @@ trait WebSocketDirectives { * the request is rejected with an [[UnsupportedWebSocketSubprotocolRejection]] rejection. * * To support several subprotocols you may chain several `handleWebSocketMessage` Routes. + * + * @group websocket */ def handleWebSocketMessagesForOptionalProtocol(handler: Flow[Message, Message, Any], subprotocol: Option[String]): Route = extractUpgradeToWebSocket { upgrade ⇒ diff --git a/project/Doc.scala b/project/Doc.scala index 7e191c5f66..43dab951c4 100644 --- a/project/Doc.scala +++ b/project/Doc.scala @@ -38,7 +38,7 @@ object Scaladoc extends AutoPlugin { def scaladocOptions(ver: String, base: File): List[String] = { 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 }