diff options
author | vlad <vlad@drivergrp.com> | 2016-07-15 19:41:26 -0400 |
---|---|---|
committer | vlad <vlad@drivergrp.com> | 2016-07-15 19:41:26 -0400 |
commit | c0d574dc6134e4f406875ea5a1301ba46602a6ec (patch) | |
tree | 606a56d184bd8c4d67f98b5aa3fafa3640a8190f /src/main/scala/com/drivergrp/core/rest.scala | |
download | driver-core-c0d574dc6134e4f406875ea5a1301ba46602a6ec.tar.gz driver-core-c0d574dc6134e4f406875ea5a1301ba46602a6ec.tar.bz2 driver-core-c0d574dc6134e4f406875ea5a1301ba46602a6ec.zip |
Initial commit with standard lib, might be used a example of cake
Diffstat (limited to 'src/main/scala/com/drivergrp/core/rest.scala')
-rw-r--r-- | src/main/scala/com/drivergrp/core/rest.scala | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/main/scala/com/drivergrp/core/rest.scala b/src/main/scala/com/drivergrp/core/rest.scala new file mode 100644 index 0000000..e121640 --- /dev/null +++ b/src/main/scala/com/drivergrp/core/rest.scala @@ -0,0 +1,92 @@ +package com.drivergrp.core + +import akka.http.scaladsl.Http +import akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import akka.http.scaladsl.server.{Directive, _} +import akka.http.scaladsl.util.FastFuture._ +import akka.stream.ActorMaterializer +import akka.util.Timeout +import com.drivergrp.core.execution.{ActorSystemModule, ExecutionContextModule} +import com.drivergrp.core.id.{Id, Name} +import com.drivergrp.core.logging.LoggerModule +import com.drivergrp.core.stats.StatsModule +import com.drivergrp.core.time.TimeRange +import com.drivergrp.core.time.provider.TimeModule +import spray.json.{DeserializationException, JsNumber, JsString, JsValue, RootJsonFormat} + +import scala.concurrent.Future +import scala.concurrent.duration._ +import scala.language.postfixOps +import scala.util.{Failure, Success, Try} +import scalaz.{Failure => _, Success => _, _} + + +object rest { + + trait RestService { + this: ActorSystemModule with LoggerModule with StatsModule with TimeModule with ExecutionContextModule => + + protected implicit val timeout = Timeout(5 seconds) + + implicit val materializer = ActorMaterializer()(actorSystem) + + + def sendRequest(request: HttpRequest): Future[HttpResponse] = { + + log.audit(s"Sending to ${request.uri} request $request") + + val requestTime = time.currentTime() + val response = Http()(actorSystem).singleRequest(request)(materializer) + + response.onComplete { + case Success(_) => + val responseTime = time.currentTime() + log.audit(s"Response from ${request.uri} to request $request is successful") + stats.recordStats(Seq("request", request.uri.toString, "success"), TimeRange(requestTime, responseTime), 1) + + case Failure(t) => + val responseTime = time.currentTime() + log.audit(s"Failed to receive response from ${request.uri} to request $request") + log.error(s"Failed to receive response from ${request.uri} to request $request", t) + stats.recordStats(Seq("request", request.uri.toString, "fail"), TimeRange(requestTime, responseTime), 1) + } (executionContext) + + response + } + } + + + object basicFormats { + + implicit def idFormat[T] = new RootJsonFormat[Id[T]] { + def write(id: Id[T]) = JsNumber(id) + + def read(value: JsValue) = value match { + case JsNumber(id) => Id[T](id.toLong) + case _ => throw new DeserializationException("Id expects number") + } + } + + implicit def nameFormat[T] = new RootJsonFormat[Name[T]] { + def write(name: Name[T]) = JsNumber(name) + + def read(value: JsValue): Name[T] = value match { + case JsString(name) => Name[T](name) + case _ => throw new DeserializationException("Name expects string") + } + } + } + + trait OptionTDirectives { + + /** + * "Unwraps" a `OptionT[Future, T]` and runs the inner route after future + * completion with the future's value as an extraction of type `Try[T]`. + */ + def onComplete[T](optionT: OptionT[Future, T]): Directive1[Try[Option[T]]] = + Directive { inner ⇒ ctx ⇒ + import ctx.executionContext + optionT.run.fast.transformWith(t ⇒ inner(Tuple1(t))(ctx)) + } + } +} |