Skip to content

Instantly share code, notes, and snippets.

@xasima
Created July 17, 2016 21:25
Show Gist options
  • Select an option

  • Save xasima/4d40da673e6029e2ed3f8aff7c61cbce to your computer and use it in GitHub Desktop.

Select an option

Save xasima/4d40da673e6029e2ed3f8aff7c61cbce to your computer and use it in GitHub Desktop.
circe in finch question
import com.twitter.app.Flag
import com.twitter.finagle.http.{Request, Response}
import com.twitter.finagle.{Http, ListeningServer, Service}
import com.twitter.server.TwitterServer
import com.twitter.util.Await
import io.circe.{Encoder, Json}
import io.finch._
import io.finch.circe._
import io.finch.circe.dropNullKeys._
import io.circe.generic.auto._
import io.circe.syntax._
import com.twitter.finagle.http.Message
import com.twitter.finagle.http.Message.ContentTypeJson
import com.twitter.io.Buf._
object RestServer extends TwitterServer {
// -- Model ----------------------------
sealed trait BaseModel
final case class Foo(id: String) extends BaseModel
final case class Bar(param: String) extends BaseModel
final case class FooBar(foo: Foo, bars:List[Bar]) extends BaseModel
// -- Backend Mock ----------------------------
def getFooList(a:String = "")= List(Foo("1"), Foo("2"))
def getBarList(a:String = "")= List(Bar("a"), Bar("b"))
def getFooBar() =FooBar(Foo("3"), List(Bar("c"),Bar("d")))
// -- Encoders ----------------------------
// QUESTION 1 - Expected to be able to use base type (BaseModel) encoder by default and
// overwrite encoder just for some specific types
// but this doesn't work
//implicit val baseEncoder = Encoder.instance[BaseModel] { f => f.asJson }
/* Error:(36, 7) not enough arguments for method asJson:
(implicit encoder: io.circe.Encoder[RestServer.BaseModel])io.circe.Json.
Unspecified value parameter encoder.
f.asJson
^
*/
// QUESTION 2 - Moreover, expected to see the build-in cicle encoder for case classes
implicit val fooEncoder = Encoder.instance[Foo] { f =>
f.asJson
}
implicit val barEncoder = Encoder.instance[Bar] { f =>
f.asJson
}
implicit val foobarEncoder = Encoder.instance[FooBar] { f =>
f.asJson
}
implicit def fooResponseEncoder: EncodeResponse[Foo] =
EncodeResponse(ContentTypeJson)(f => Utf8(Map("data" -> f).asJson.noSpaces))
implicit def barResponseEncoder: EncodeResponse[Bar] =
EncodeResponse(ContentTypeJson)(b => Utf8(Map("data" -> b).asJson.noSpaces))
// QUESTION 3: The same, why need to explicitly declare natural encoding for case classes
implicit def fooListResponseEncoder: EncodeResponse[List[Foo]] =
EncodeResponse(ContentTypeJson)(fooList => Utf8(Json.arr(fooList map {_.asJson}:_*).asJson.noSpaces))
implicit def barListResponseEncoder: EncodeResponse[List[Bar]] =
EncodeResponse(ContentTypeJson)(barList => Utf8(Json.arr(barList map {_.asJson}:_*).asJson.noSpaces))
// QUESTION 4: Is something may be omitted, relying on previous encoders ?
// {foo: {"id":"1"}, bars: [{param:"a"}, {"param":"b"}]
//
implicit def fooBarResponseEncoder: EncodeResponse[FooBar] =
EncodeResponse(ContentTypeJson)(f =>
Utf8(Map("foo" -> f.foo.asJson,
"bars" -> Json.arr(f.bars map {_. asJson}: _*)).asJson.noSpaces))
// -- Endpoints ----------------------------
val fooListApi: Endpoint[List[Foo]] = get("v1" :: "foos" ) {
Ok(getFooList())
}
val fooApi: Endpoint[Foo] = get("v1" :: "foos" :: string ) {
(a: String) =>
Ok(getFooList(a)(0))
}
val barListApi: Endpoint[List[Bar]] = get("v1" :: "bars" ) {
Ok(getBarList() )
}
val barApi: Endpoint[Bar] = get("v1" :: "bars" :: string ) {
(a: String) =>
Ok(getBarList(a)(0) )
}
val foobarApi: Endpoint[FooBar] = get("v1" :: "foobar" ) {
Ok(getFooBar)
}
// Finch-finagle service
val apiService: Service[Request, Response] =
(fooListApi :+: fooApi :+: barListApi :+: barApi :+: foobarApi).handle({
case e: Exception => NotFound(e)
}).toService
val port: Flag[Int] = flag("port", 8081, "TCP port for HTTP server")
def main(): Unit = {
val server: ListeningServer = Http.server.serve(s":${port()}", apiService)
println("Listening: " + port() )
onExit { server.close() }
Await.ready(adminHttpServer)
}
}
@xasima
Copy link
Copy Markdown
Author

xasima commented Jul 18, 2016

Thanks @vkostyukov! Fixed just by removing import io.finch.circe.dropNullKeys._ everywhere.
Discussion was held here https://gitter.im/finagle/finch?at=578c7988196179690eff3eca

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment