aboutsummaryrefslogtreecommitdiff
path: root/core-rest/src/main/scala/xyz/driver/core/rest/RestService.scala
blob: 09d98b855a5acce49397f1c623f9ea49276aea3e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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)
}