Skip to content

Instantly share code, notes, and snippets.

@samuelorji
Last active April 10, 2020 15:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samuelorji/56aa034ed9d3ed6677514492410fee1a to your computer and use it in GitHub Desktop.
Save samuelorji/56aa034ed9d3ed6677514492410fee1a to your computer and use it in GitHub Desktop.
trait MarshallingSupport
extends SprayJsonSupport
with DefaultJsonProtocol with Runtime[Unit] { self =>
//implicit marshallers for my return Type A
implicit val todoItemFormatter = jsonFormat2(TodoItem)
implicit val todoNameFormatter = jsonFormat1(TodoName)
sealed trait ErrorToHttpResponse[E] {
def toHttpResponse(value: E): HttpResponse
}
private def generateHttpResponseFromError(error : TodoError) : HttpResponse = {
error match {
case ToDoItemError(errorMsg) =>
HttpResponse(StatusCodes.NotFound, entity = HttpEntity(errorMsg))
case QueryError(errorMsg) =>
HttpResponse(StatusCodes.BadRequest, entity = HttpEntity(errorMsg))
case DbError(errorMsg) =>
HttpResponse(StatusCodes.InternalServerError, entity = HttpEntity(errorMsg))
}
}
implicit def errorHttp = new ErrorToHttpResponse[TodoError] {
override def toHttpResponse(value: TodoError): HttpResponse = {
generateHttpResponseFromError(value)
}
}
implicit val errorMarshaller: Marshaller[TodoError, HttpResponse] = {
Marshaller { implicit ec => error =>
val response = generateHttpResponseFromError(error)
PredefinedToResponseMarshallers.fromResponse(response)
}
}
implicit def ioEffectToMarshallable[E, A]
(implicit m1: Marshaller[A, HttpResponse], m2: Marshaller[E, HttpResponse])
: Marshaller[IO[E, A], HttpResponse] = {
//Factory method for creating marshallers
Marshaller { implicit ec =>
effect =>
val promise = Promise[List[Marshalling[HttpResponse]]]()
val marshalledEffect: IO[Throwable, List[Marshalling[HttpResponse]]] =
//foldM creates a new effect
//similar to flatMap
effect.foldM(
err => IO.fromFuture(_ => m2(err)),
suc => IO.fromFuture(_ => m1(suc))
)
self.unsafeRunAsync(marshalledEffect) { done =>
done.fold(failed => promise.failure(failed.squash),
success => promise.success(success))
}
promise.future
}
}
implicit def standardRouteToRoute[E](effect: IO[E, StandardRoute])
(implicit errToHttp: ErrorToHttpResponse[E]): Route = {
//type Route = RequestContext ⇒ Future[RouteResult]
ctx =>
val promise = Promise[RouteResult]()
//fold doesn't return a new effect.
// similar to map
val foldedEffect = effect.fold(
err => { Future.successful(Complete(errToHttp.toHttpResponse(err))) },
suc => suc.apply(ctx)
)
self.unsafeRunAsync(foldedEffect) { done =>
done.fold(
err => promise.failure(err.squash),
suc => promise.completeWith(suc)
)
}
promise.future
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment