Skip to content

Instantly share code, notes, and snippets.

@mkf-simpson
Created February 13, 2019 21:02
Show Gist options
  • Save mkf-simpson/5ef074862a7981520e4aca3661765000 to your computer and use it in GitHub Desktop.
Save mkf-simpson/5ef074862a7981520e4aca3661765000 to your computer and use it in GitHub Desktop.
Finch with Circe
package finchtest
import cats.effect._
import cats.implicits._
import com.twitter.finagle.Http
import com.twitter.util
import io.circe._
import io.circe.generic.extras.{Configuration => CirceExtraConfiguration}
import io.circe.generic.extras.auto._
import io.finch._
import io.finch.circe._
case class Entity(name: String, id: String = java.util.UUID.randomUUID().toString)
class HttpJsonService[F[_]: Effect] extends Endpoint.Module[F] {
implicit val genDevConfig: CirceExtraConfiguration =
CirceExtraConfiguration.default.withDefaults
def json = post("json" :: jsonBody[Entity]) { entity: Entity =>
Ok(entity).pure[F]
}
def api = json.toServiceAs[Application.Json]
}
object Circe extends IOApp {
def whenTerminated[F[_]](implicit A: Async[F]): F[Unit] = {
A.async(cb => {
sys.addShutdownHook(cb(Right(())))
})
}
override def run(args: List[String]): IO[ExitCode] = for {
http <- IO(Http.server.withStreaming(true).serve(s"0.0.0.0:8086", new HttpJsonService[IO].api))
stop <- IO.race(whenTerminated[IO], IO(util.Await.ready(http)))
code <- stop match {
case Left(_) => IO(http.close(util.Duration.Top)).map(_ => 0)
case Right(_) => IO.pure(1)
}
} yield ExitCode(code)
}
@mkf-simpson
Copy link
Author

curl -X POST -H "Content-Type: application/json" --data '{"name": "abc"}' http://localhost:8086/json
{"name":"abc","id":"1f720c63-8d0c-4eda-bb27-601c3887a1c0"}%
curl -X POST -H "Content-Type: application/json" --data '{"name": "abcd"}' http://localhost:8086/json
{"name":"abcd","id":"1f720c63-8d0c-4eda-bb27-601c3887a1c0"}%
curl -X POST -H "Content-Type: application/json" --data '{"name": "abcde"}' http://localhost:8086/json
{"name":"abcde","id":"1f720c63-8d0c-4eda-bb27-601c3887a1c0"}%

@mkf-simpson
Copy link
Author

Example with plain circe (for ammonite):

{
  import $ivy.`io.circe::circe-generic:0.11.0`, $ivy.`io.circe::circe-parser:0.11.0`, $ivy.`io.circe::circe-generic-extras:0.11.0`
  import io.circe._
  import io.circe.generic.extras.{Configuration => CirceExtraConfiguration}
  import io.circe.generic.extras.auto._
  import io.circe.parser.decode

  implicit val genDevConfig: CirceExtraConfiguration = CirceExtraConfiguration.default.withDefaults

  case class Test(i: Int, s: String = UUID.randomUUID().toString, r: Double = scala.util.Random.nextDouble())
  println(decode[Test]("""{"i": 1}"""))
  println(decode[Test]("""{"i": 1}"""))
  println(decode[Test]("""{"i": 1}"""))
}


Right(Test(1,b0e90e7f-b4a2-4421-98fa-295fe601a3cc,0.6274328064334737))
Right(Test(1,e6c7586b-45d0-486b-94d1-384e2a61bcaa,0.07286186812472872))
Right(Test(1,52d6efad-b496-4e63-bdd9-e1a988a3ed2a,0.6893038938162794))

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