aboutsummaryrefslogtreecommitdiff
path: root/core-rest/src/main/scala/xyz/driver/core/rest/RestService.scala
diff options
context:
space:
mode:
Diffstat (limited to 'core-rest/src/main/scala/xyz/driver/core/rest/RestService.scala')
-rw-r--r--core-rest/src/main/scala/xyz/driver/core/rest/RestService.scala86
1 files changed, 86 insertions, 0 deletions
diff --git a/core-rest/src/main/scala/xyz/driver/core/rest/RestService.scala b/core-rest/src/main/scala/xyz/driver/core/rest/RestService.scala
new file mode 100644
index 0000000..09d98b8
--- /dev/null
+++ b/core-rest/src/main/scala/xyz/driver/core/rest/RestService.scala
@@ -0,0 +1,86 @@
+package xyz.driver.core.rest
+
+import akka.http.scaladsl.model._
+import akka.http.scaladsl.unmarshalling.{Unmarshal, Unmarshaller}
+import akka.stream.Materializer
+
+import scala.concurrent.{ExecutionContext, Future}
+import scalaz.{ListT, OptionT}
+
+trait RestService extends Service {
+
+ import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
+ import spray.json._
+
+ protected implicit val exec: ExecutionContext
+ protected implicit val materializer: Materializer
+
+ implicit class ResponseEntityFoldable(entity: Unmarshal[ResponseEntity]) {
+ def fold[T](default: => T)(implicit um: Unmarshaller[ResponseEntity, T]): Future[T] =
+ if (entity.value.isKnownEmpty()) Future.successful[T](default) else entity.to[T]
+ }
+
+ protected def unitResponse(request: Future[Unmarshal[ResponseEntity]]): OptionT[Future, Unit] =
+ OptionT[Future, Unit](request.flatMap(_.to[String]).map(_ => Option(())))
+
+ protected def optionalResponse[T](request: Future[Unmarshal[ResponseEntity]])(
+ implicit um: Unmarshaller[ResponseEntity, Option[T]]): OptionT[Future, T] =
+ OptionT[Future, T](request.flatMap(_.fold(Option.empty[T])))
+
+ protected def listResponse[T](request: Future[Unmarshal[ResponseEntity]])(
+ implicit um: Unmarshaller[ResponseEntity, List[T]]): ListT[Future, T] =
+ ListT[Future, T](request.flatMap(_.fold(List.empty[T])))
+
+ protected def jsonEntity(json: JsValue): RequestEntity =
+ HttpEntity(ContentTypes.`application/json`, json.compactPrint)
+
+ protected def mergePatchJsonEntity(json: JsValue): RequestEntity =
+ HttpEntity(PatchDirectives.`application/merge-patch+json`, json.compactPrint)
+
+ protected def get(baseUri: Uri, path: String, query: Seq[(String, String)] = Seq.empty) =
+ HttpRequest(HttpMethods.GET, endpointUri(baseUri, path, query))
+
+ protected def post(baseUri: Uri, path: String, httpEntity: RequestEntity) =
+ HttpRequest(HttpMethods.POST, endpointUri(baseUri, path), entity = httpEntity)
+
+ protected def postJson(baseUri: Uri, path: String, json: JsValue) =
+ HttpRequest(HttpMethods.POST, endpointUri(baseUri, path), entity = jsonEntity(json))
+
+ protected def put(baseUri: Uri, path: String, httpEntity: RequestEntity) =
+ HttpRequest(HttpMethods.PUT, endpointUri(baseUri, path), entity = httpEntity)
+
+ protected def putJson(baseUri: Uri, path: String, json: JsValue) =
+ HttpRequest(HttpMethods.PUT, endpointUri(baseUri, path), entity = jsonEntity(json))
+
+ protected def patch(baseUri: Uri, path: String, httpEntity: RequestEntity) =
+ HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, path), entity = httpEntity)
+
+ protected def patchJson(baseUri: Uri, path: String, json: JsValue) =
+ HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, path), entity = jsonEntity(json))
+
+ protected def mergePatchJson(baseUri: Uri, path: String, json: JsValue) =
+ HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, path), entity = mergePatchJsonEntity(json))
+
+ protected def delete(baseUri: Uri, path: String, query: Seq[(String, String)] = Seq.empty) =
+ HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, path, query))
+
+ protected def endpointUri(baseUri: Uri, path: String): Uri =
+ baseUri.withPath(Uri.Path(path))
+
+ protected def endpointUri(baseUri: Uri, path: String, query: Seq[(String, String)]): Uri =
+ baseUri.withPath(Uri.Path(path)).withQuery(Uri.Query(query: _*))
+
+ protected def responseToListResponse[T: JsonFormat](pagination: Option[Pagination])(
+ response: HttpResponse): Future[ListResponse[T]] = {
+ import DefaultJsonProtocol._
+ val resourceCount = response.headers
+ .find(_.name() equalsIgnoreCase ContextHeaders.ResourceCount)
+ .map(_.value().toInt)
+ .getOrElse(0)
+ val meta = ListResponse.Meta(resourceCount, pagination.getOrElse(Pagination(resourceCount max 1, 1)))
+ Unmarshal(response.entity).to[List[T]].map(ListResponse(_, meta))
+ }
+
+ protected def responseToListResponse[T: JsonFormat](pagination: Pagination)(
+ response: HttpResponse): Future[ListResponse[T]] = responseToListResponse(Some(pagination))(response)
+}