Skip to content

Instantly share code, notes, and snippets.

@xasima
Last active August 29, 2015 14:20
Show Gist options
  • Select an option

  • Save xasima/56e5fe7c841199475f5c to your computer and use it in GitHub Desktop.

Select an option

Save xasima/56e5fe7c841199475f5c to your computer and use it in GitHub Desktop.
finagle-finch with argonaut-json implicit conversion
// These are snippets based on the recent finch demo package.
// Some modification are added to eliminate usage of ToJson trait,
// but use argonaut Json via implicits instead.
// The purpose of ToJson trait removal is to bypass compilers errors on
// Service[AuthRequest, Seq[argonaut.Json]] to Service[AuthRequest, Json]]
// conversion.
// See current compilers errors at the bottom of the gist
// model.scala snippet
// ----- Domain classes and utils -------------------------------------------
case class User(val id: Long, val name: String) // No extends of ToJson
object User {
implicit def decodeJson: DecodeJson[User] = DecodeJson(hcursor =>
for {
name <- (hcursor --\ "name").as[String]
id <- (hcursor --\ "id").as[Long]
} yield new User( id, name))
implicit def encodeJson: EncodeJson[User] =
EncodeJson((a: User) =>
("id" := a.id) ->: ("name" := a.name) ->: jEmptyObject)
}
/**
* An implicit class that converts a service that returns a sequence of `Json`
* objects into a service that returns `Json` object.
*/
implicit class SeqToJson[A](s: Service[A, Seq[Json]]) extends Service[A, Json] {
private[server] def seqToJson(seq: Seq[Json]) =
Json.array(seq: _*)
def apply(req: A): Future[Json] = s(req) map seqToJson
}
// ----- / Domain classes and utils -------------------------------------------
// service.scala snippet
// ----- REST Service methods impl -------------------------------------------
case class GetUser(userId: Long) extends Service[AuthRequest, User] {
def apply(req: AuthRequest): Future[User] = Db.select(userId) flatMap {
case Some(user) => user.toFuture
case None => UserNotFound(userId).toFutureException[User]
}
}
case class GetUsers() extends Service[AuthRequest, Seq[User]] {
def apply(req: AuthRequest): Future[Seq[User] ] =
Seq(User(1, "foo"), User(2, "bar")).toFuture
}
// ----- / REST Service methods impl -------------------------------------------
// ----- Endpoints -------------------------------------------
// endpoint.scala
import model._
import io.finch.route._
// Not sure why this is needed since we do have User.encodeJson implicit,
// and SeqToJson implicit already
implicit def anyToJson[A](a: A)(implicit e: EncodeJson[A]): Json = e(a)
// User endpoint.
val restEndpoint: Endpoint[AuthRequest, Json] =
// It is supposed that the following GetUser of the
// Service[AuthRequest, User] type would be converted to Service[AuthRequest, Json] via
// User.encodeJson implicit
(Get / "users" / long /> GetUser ) |
// and GetUsers of the Service[AuthRequest, Seq[User]] type would be converted to
// Service[AuthRequest, Seq[Json]]
// via the same User.encodeJson implicit, and later the conversion
// Service[AuthRequest, Seq[Json]] to Service[AuthRequest, Json] occurs via
// SeqToJson implicit
(Get / "users" /> GetUsers )
// But compiler error occurs on GetUsers
// Error:(38, 61) type mismatch;
// found : com.xxx.xxx.server.service.GetUsers.type
// required: com.twitter.finagle.Service[com.xxx.xxx.internals.AuthRequest,argonaut.Json]
// (Get / "users" / long /> GetUser ) | (Get / "users" /> GetUsers )
^
// It the later GetUsers part of endpoint is commented out, then the mismatch occurs on plain GetUser
// Error:(38, 31) type mismatch;
// found : com.xxx.xxx.server.service.GetUser.type
// required: Long => com.twitter.finagle.Service[com.xxx.xxx.internals.AuthRequest,argonaut.Json]
// (Get / "users" / long /> GetUser )
^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment