aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jakob@driver.xyz>2017-08-03 17:49:50 -0700
committerJakob Odersky <jakob@driver.xyz>2017-08-16 19:26:10 -0700
commitdd9ae7da10818174541f415854e6a6f7b1791e10 (patch)
treedf952070620b6af8afa123ba1ae7ab0312f2ac1c
parent0783832d1c58f9463e85ed504fc0edbfaedc09c5 (diff)
downloadrest-query-dd9ae7da10818174541f415854e6a6f7b1791e10.tar.gz
rest-query-dd9ae7da10818174541f415854e6a6f7b1791e10.tar.bz2
rest-query-dd9ae7da10818174541f415854e6a6f7b1791e10.zip
Add completion directives for service replies (also scalafmt)
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala56
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala12
2 files changed, 53 insertions, 15 deletions
diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala b/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala
index bb6a9e3..9b57b90 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala
@@ -1,7 +1,13 @@
package xyz.driver.pdsuicommon.http
+import akka.http.scaladsl.marshalling._
import akka.http.scaladsl.server.Directive1
import akka.http.scaladsl.server.Directives._
+import akka.http.scaladsl.server.Route
+import xyz.driver.pdsuicommon.auth._
+import xyz.driver.pdsuicommon.error._
+import xyz.driver.pdsuicommon.error.DomainError._
+import xyz.driver.pdsuicommon.error.ErrorsResponse.ResponseError
import xyz.driver.pdsuicommon.parsers._
import xyz.driver.pdsuicommon.db.{Pagination, Sorting, SearchFilterExpr}
import scala.util._
@@ -12,17 +18,59 @@ trait Directives {
case (size, number) => Pagination(size, number)
}
- def sorted(validDimensions: Set[String]): Directive1[Sorting] = parameterSeq.flatMap{ params =>
+ def sorted(validDimensions: Set[String]): Directive1[Sorting] = parameterSeq.flatMap { params =>
SortingParser.parse(validDimensions, params) match {
case Success(sorting) => provide(sorting)
- case Failure(ex) => failWith(ex)
+ case Failure(ex) => failWith(ex)
}
}
- val searchFiltered: Directive1[SearchFilterExpr] = parameterSeq.flatMap{ params =>
+ val searchFiltered: Directive1[SearchFilterExpr] = parameterSeq.flatMap { params =>
SearchFilterParser.parse(params) match {
case Success(sorting) => provide(sorting)
- case Failure(ex) => failWith(ex)
+ case Failure(ex) => failWith(ex)
+ }
+ }
+
+ @annotation.implicitNotFound("An ApiExtractor is required to complete service replies.")
+ trait ApiExtractor[Reply, Api] extends PartialFunction[Reply, Api]
+ object ApiExtractor {
+ // Note: make sure the Reply here is the most common response
+ // type. The specific entity type should be handled in the partial
+ // function. E.g. `apply[GetByIdReply, Api]{case
+ // GetByIdReply.Entity => Api}`
+ def apply[Reply, Api](pf: PartialFunction[Reply, Api]): ApiExtractor[Reply, Api] = new ApiExtractor[Reply, Api] {
+ override def isDefinedAt(x: Reply) = pf.isDefinedAt(x)
+ override def apply(x: Reply) = pf.apply(x)
+ }
+ }
+
+ def completeService[Reply, Api](reply: => Reply)(implicit requestId: RequestId,
+ apiExtractor: ApiExtractor[Reply, Api],
+ apiMarshaller: ToEntityMarshaller[Api],
+ errorMarshaller: ToEntityMarshaller[ErrorsResponse]): Route = {
+
+ def errorResponse(err: DomainError) =
+ ErrorsResponse(Seq(ResponseError(None, err.getMessage, ErrorCode.Unspecified)), requestId)
+
+ // TODO: rather than completing the bad requests here, we should
+ // consider throwing a corresponding exception and then handling
+ // it in an error handler
+ reply match {
+ case apiReply if apiExtractor.isDefinedAt(apiReply) =>
+ complete(apiExtractor(reply))
+ case err: NotFoundError =>
+ complete(401 -> errorResponse(err))
+ case err: AuthenticationError =>
+ complete(401 -> errorResponse(err))
+ case err: AuthorizationError =>
+ complete(403 -> errorResponse(err))
+ case err: DomainError =>
+ complete(400 -> errorResponse(err))
+ case other =>
+ val msg = s"Got unexpected response type in completion directive: ${other.getClass.getSimpleName}"
+ val res = ErrorsResponse(Seq(ResponseError(None, msg, ErrorCode.Unspecified)), requestId)
+ complete(500 -> res)
}
}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala
index f23b1b0..fb5a6b9 100644
--- a/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala
+++ b/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala
@@ -1,8 +1,5 @@
package xyz.driver.pdsuicommon.parsers
-//import play.api.libs.json._
-//import xyz.driver.pdsuicommon.utils.WritesUtils
-
import scala.util.{Failure, Success, Try}
class Dimensions(private val xs: Set[String] = Set.empty) {
@@ -11,15 +8,8 @@ class Dimensions(private val xs: Set[String] = Set.empty) {
object DimensionsParser {
- /*
- private class DimensionsWrapper[T](dimensions: Dimensions)(implicit orig: Writes[T]) extends Writes[T] {
- private val filteredWrites = WritesUtils.filterKeys[T](dimensions.contains)
- override def writes(o: T): JsValue = filteredWrites.writes(o)
- }
- */
-
def tryParse(query: Seq[(String, String)]): Try[Dimensions] = {
- query.collect{ case ("dimensions", value) => value } match {
+ query.collect { case ("dimensions", value) => value } match {
case Nil => Success(new Dimensions())
case x +: Nil =>